diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/llaccountingquotamanager.cpp | 528 | ||||
-rw-r--r-- | indra/newview/lldrawpoolbump.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llfeaturemanager.cpp | 1614 | ||||
-rw-r--r-- | indra/newview/llfloaterbuyland.cpp | 18 | ||||
-rw-r--r-- | indra/newview/llpanelobject.cpp | 3998 | ||||
-rw-r--r-- | indra/newview/llviewermessage.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llviewerobject.cpp | 11424 | ||||
-rw-r--r-- | indra/newview/llviewerobject.h | 1650 | ||||
-rw-r--r-- | indra/newview/llviewerparcelmgr.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llviewerprecompiledheaders.h | 4 | ||||
-rw-r--r-- | indra/newview/llviewertexturelist.cpp | 4 |
11 files changed, 9630 insertions, 9630 deletions
diff --git a/indra/newview/llaccountingquotamanager.cpp b/indra/newview/llaccountingquotamanager.cpp index ada74ea44c..d11b86db15 100644 --- a/indra/newview/llaccountingquotamanager.cpp +++ b/indra/newview/llaccountingquotamanager.cpp @@ -1,264 +1,264 @@ -/**
- * @file LLAccountingQuotaManager.cpp
- * @ Handles the setting and accessing for costs associated with mesh
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llaccountingquotamanager.h"
-#include "llagent.h"
-#include "llviewerregion.h"
-#include "llviewerobject.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llparcel.h"
-
-//===============================================================================
-LLAccountingQuotaManager::LLAccountingQuotaManager()
-{
-}
-//===============================================================================
-class LLAccountingQuotaResponder : public LLCurl::Responder
-{
-public:
- LLAccountingQuotaResponder( const LLSD& objectIDs )
- : mObjectIDs( objectIDs )
- {
- }
-
- void clearPendingRequests ( void )
- {
- for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter )
- {
- LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( iter->asUUID() );
- }
- }
-
- void error( U32 statusNum, const std::string& reason )
- {
- llwarns << "Transport error "<<reason<<llendl;
- //prep#do we really want to remove all because of one failure - verify
- clearPendingRequests();
- }
-
- void result( const LLSD& content )
- {
- if ( !content.isMap() || content.has("error") )
- {
- llwarns << "Error on fetched data"<< llendl;
- //prep#do we really want to remove all because of one failure - verify
- clearPendingRequests();
- return;
- }
-
- //Differentiate what the incoming caps could be from the data
- //bool VOContent = content.has("Objects");
- bool containsParcel = content.has("parcel");
- bool containsSelection = content.has("selected");
- //bool VORegion = content.has("region");
-
- //Loop over the stored object ids checking against the incoming data
- for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter )
- {
- LLUUID objectID = iter->asUUID();
-
- LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( objectID );
-
- if ( containsParcel )
- {
- //Typically should be one
- S32 dataCount = content["parcel"].size();
- for(S32 i = 0; i < dataCount; i++)
- {
- //prep#todo verify that this is safe, otherwise just add a bool
- S32 parcelId = 0;
- S32 parcelOwner = 0;
- if ( content["parcel"][i].has("parcel_id") )
- {
- parcelId = content["parcel"][i]["parcel_id"].asInteger();
- }
- if ( content["parcel"][i].has("parcel_owner") )
- {
- parcelOwner = content["parcel"][i]["parcel_owner"].asInteger();
- }
-
- F32 ownerRenderCost = 0;
- F32 ownerPhysicsCost = 0;
- F32 ownerNetworkCost = 0;
- F32 ownerSimulationCost = 0;
-
- F32 groupRenderCost = 0;
- F32 groupPhysicsCost = 0;
- F32 groupNetworkCost = 0;
- F32 groupSimulationCost = 0;
-
- F32 otherRenderCost = 0;
- F32 otherPhysicsCost = 0;
- F32 otherNetworkCost = 0;
- F32 otherSimulationCost = 0;
-
- F32 totalRenderCost = 0;
- F32 totalPhysicsCost = 0;
- F32 totalNetworkCost = 0;
- F32 totalSimulationCost = 0;
-
- if ( content["parcel"][i].has("owner") )
- {
- ownerRenderCost = content["parcel"][i]["owner"]["render"].asReal();
- ownerPhysicsCost = content["parcel"][i]["owner"]["physics"].asReal();
- ownerNetworkCost = content["parcel"][i]["owner"]["network"].asReal();
- ownerSimulationCost = content["parcel"][i]["owner"]["simulation"].asReal();
-
- }
- if ( content["parcel"][i].has("group") )
- {
- groupRenderCost = content["parcel"][i]["group"]["render"].asReal();
- groupPhysicsCost = content["parcel"][i]["group"]["physics"].asReal();
- groupNetworkCost = content["parcel"][i]["group"]["network"].asReal();
- groupSimulationCost = content["parcel"][i]["group"]["simulation"].asReal();
-
- }
- if ( content["parcel"][i].has("other") )
- {
- otherRenderCost = content["parcel"][i]["other"]["render"].asReal();
- otherPhysicsCost = content["parcel"][i]["other"]["physics"].asReal();
- otherNetworkCost = content["parcel"][i]["other"]["network"].asReal();
- otherSimulationCost = content["parcel"][i]["other"]["simulation"].asReal();
- }
-
- if ( content["parcel"][i].has("total") )
- {
- totalRenderCost = content["parcel"][i]["total"]["render"].asReal();
- totalPhysicsCost = content["parcel"][i]["total"]["physics"].asReal();
- totalNetworkCost = content["parcel"][i]["total"]["network"].asReal();
- totalSimulationCost = content["parcel"][i]["total"]["simulation"].asReal();
-
- }
-
- ParcelQuota parcelQuota( ownerRenderCost, ownerPhysicsCost, ownerNetworkCost, ownerSimulationCost,
- groupRenderCost, groupPhysicsCost, groupNetworkCost, groupSimulationCost,
- otherRenderCost, otherPhysicsCost, otherNetworkCost, otherSimulationCost,
- totalRenderCost, totalPhysicsCost, totalNetworkCost, totalSimulationCost );
- //Update the Parcel
- LLParcel* pParcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel();
- if ( pParcel )
- {
- pParcel->updateQuota( objectID, parcelQuota );
- }
- }
- }
- else
- if ( containsSelection )
- {
- S32 dataCount = content["selected"].size();
- for(S32 i = 0; i < dataCount; i++)
- {
-
- F32 renderCost = 0;
- F32 physicsCost = 0;
- F32 networkCost = 0;
- F32 simulationCost = 0;
-
- S32 localId = 0;
-
- localId = content["selected"][i]["local_id"].asInteger();
- renderCost = content["selected"][i]["render"].asReal();
- physicsCost = content["selected"][i]["physics"].asReal();
- networkCost = content["selected"][i]["network"].asReal();
- simulationCost = content["selected"][i]["simulation"].asReal();
-
- SelectionQuota selectionQuota( localId, renderCost, physicsCost, networkCost, simulationCost );
-
- //Update the objects
- //gObjectList.updateQuota( localId, selectionQuota );
-
- }
- }
- else
- {
- //Nothing in string
- LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( objectID );
- }
- }
- }
-
-private:
- //List of posted objects
- LLSD mObjectIDs;
-};
-//===============================================================================
-void LLAccountingQuotaManager::fetchQuotas( const std::string& url )
-{
- // Invoking system must have already determined capability availability
- if ( !url.empty() )
- {
- LLSD objectList;
- U32 objectIndex = 0;
- IDIt IDIter = mUpdateObjectQuota.begin();
- IDIt IDIterEnd = mUpdateObjectQuota.end();
-
- for ( ; IDIter != IDIterEnd; ++IDIter )
- {
- // Check to see if a request for this object has already been made.
- if ( mPendingObjectQuota.find( *IDIter ) == mPendingObjectQuota.end() )
- {
- mPendingObjectQuota.insert( *IDIter );
- objectList[objectIndex++] = *IDIter;
- }
- }
-
- mUpdateObjectQuota.clear();
-
- //Post results
- if ( objectList.size() > 0 )
- {
- LLSD dataToPost = LLSD::emptyMap();
- dataToPost["object_ids"] = objectList;
- LLHTTPClient::post( url, dataToPost, new LLAccountingQuotaResponder( objectList ));
- }
- }
- else
- {
- //url was empty - warn & continue
- llwarns<<"Supplied url is empty "<<llendl;
- mUpdateObjectQuota.clear();
- mPendingObjectQuota.clear();
- }
-}
-//===============================================================================
-void LLAccountingQuotaManager::updateObjectCost( const LLUUID& objectID )
-{
- mUpdateObjectQuota.insert( objectID );
-}
-//===============================================================================
-void LLAccountingQuotaManager::removePendingObjectQuota( const LLUUID& objectID )
-{
- mPendingObjectQuota.erase( objectID );
-}
-//===============================================================================
+/** + * @file LLAccountingQuotaManager.cpp + * @ Handles the setting and accessing for costs associated with mesh + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llaccountingquotamanager.h" +#include "llagent.h" +#include "llviewerregion.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llparcel.h" + +//=============================================================================== +LLAccountingQuotaManager::LLAccountingQuotaManager() +{ +} +//=============================================================================== +class LLAccountingQuotaResponder : public LLCurl::Responder +{ +public: + LLAccountingQuotaResponder( const LLSD& objectIDs ) + : mObjectIDs( objectIDs ) + { + } + + void clearPendingRequests ( void ) + { + for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter ) + { + LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( iter->asUUID() ); + } + } + + void error( U32 statusNum, const std::string& reason ) + { + llwarns << "Transport error "<<reason<<llendl; + //prep#do we really want to remove all because of one failure - verify + clearPendingRequests(); + } + + void result( const LLSD& content ) + { + if ( !content.isMap() || content.has("error") ) + { + llwarns << "Error on fetched data"<< llendl; + //prep#do we really want to remove all because of one failure - verify + clearPendingRequests(); + return; + } + + //Differentiate what the incoming caps could be from the data + //bool VOContent = content.has("Objects"); + bool containsParcel = content.has("parcel"); + bool containsSelection = content.has("selected"); + //bool VORegion = content.has("region"); + + //Loop over the stored object ids checking against the incoming data + for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter ) + { + LLUUID objectID = iter->asUUID(); + + LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( objectID ); + + if ( containsParcel ) + { + //Typically should be one + S32 dataCount = content["parcel"].size(); + for(S32 i = 0; i < dataCount; i++) + { + //prep#todo verify that this is safe, otherwise just add a bool + S32 parcelId = 0; + S32 parcelOwner = 0; + if ( content["parcel"][i].has("parcel_id") ) + { + parcelId = content["parcel"][i]["parcel_id"].asInteger(); + } + if ( content["parcel"][i].has("parcel_owner") ) + { + parcelOwner = content["parcel"][i]["parcel_owner"].asInteger(); + } + + F32 ownerRenderCost = 0; + F32 ownerPhysicsCost = 0; + F32 ownerNetworkCost = 0; + F32 ownerSimulationCost = 0; + + F32 groupRenderCost = 0; + F32 groupPhysicsCost = 0; + F32 groupNetworkCost = 0; + F32 groupSimulationCost = 0; + + F32 otherRenderCost = 0; + F32 otherPhysicsCost = 0; + F32 otherNetworkCost = 0; + F32 otherSimulationCost = 0; + + F32 totalRenderCost = 0; + F32 totalPhysicsCost = 0; + F32 totalNetworkCost = 0; + F32 totalSimulationCost = 0; + + if ( content["parcel"][i].has("owner") ) + { + ownerRenderCost = content["parcel"][i]["owner"]["render"].asReal(); + ownerPhysicsCost = content["parcel"][i]["owner"]["physics"].asReal(); + ownerNetworkCost = content["parcel"][i]["owner"]["network"].asReal(); + ownerSimulationCost = content["parcel"][i]["owner"]["simulation"].asReal(); + + } + if ( content["parcel"][i].has("group") ) + { + groupRenderCost = content["parcel"][i]["group"]["render"].asReal(); + groupPhysicsCost = content["parcel"][i]["group"]["physics"].asReal(); + groupNetworkCost = content["parcel"][i]["group"]["network"].asReal(); + groupSimulationCost = content["parcel"][i]["group"]["simulation"].asReal(); + + } + if ( content["parcel"][i].has("other") ) + { + otherRenderCost = content["parcel"][i]["other"]["render"].asReal(); + otherPhysicsCost = content["parcel"][i]["other"]["physics"].asReal(); + otherNetworkCost = content["parcel"][i]["other"]["network"].asReal(); + otherSimulationCost = content["parcel"][i]["other"]["simulation"].asReal(); + } + + if ( content["parcel"][i].has("total") ) + { + totalRenderCost = content["parcel"][i]["total"]["render"].asReal(); + totalPhysicsCost = content["parcel"][i]["total"]["physics"].asReal(); + totalNetworkCost = content["parcel"][i]["total"]["network"].asReal(); + totalSimulationCost = content["parcel"][i]["total"]["simulation"].asReal(); + + } + + ParcelQuota parcelQuota( ownerRenderCost, ownerPhysicsCost, ownerNetworkCost, ownerSimulationCost, + groupRenderCost, groupPhysicsCost, groupNetworkCost, groupSimulationCost, + otherRenderCost, otherPhysicsCost, otherNetworkCost, otherSimulationCost, + totalRenderCost, totalPhysicsCost, totalNetworkCost, totalSimulationCost ); + //Update the Parcel + LLParcel* pParcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); + if ( pParcel ) + { + pParcel->updateQuota( objectID, parcelQuota ); + } + } + } + else + if ( containsSelection ) + { + S32 dataCount = content["selected"].size(); + for(S32 i = 0; i < dataCount; i++) + { + + F32 renderCost = 0; + F32 physicsCost = 0; + F32 networkCost = 0; + F32 simulationCost = 0; + + S32 localId = 0; + + localId = content["selected"][i]["local_id"].asInteger(); + renderCost = content["selected"][i]["render"].asReal(); + physicsCost = content["selected"][i]["physics"].asReal(); + networkCost = content["selected"][i]["network"].asReal(); + simulationCost = content["selected"][i]["simulation"].asReal(); + + SelectionQuota selectionQuota( localId, renderCost, physicsCost, networkCost, simulationCost ); + + //Update the objects + //gObjectList.updateQuota( localId, selectionQuota ); + + } + } + else + { + //Nothing in string + LLAccountingQuotaManager::getInstance()->removePendingObjectQuota( objectID ); + } + } + } + +private: + //List of posted objects + LLSD mObjectIDs; +}; +//=============================================================================== +void LLAccountingQuotaManager::fetchQuotas( const std::string& url ) +{ + // Invoking system must have already determined capability availability + if ( !url.empty() ) + { + LLSD objectList; + U32 objectIndex = 0; + IDIt IDIter = mUpdateObjectQuota.begin(); + IDIt IDIterEnd = mUpdateObjectQuota.end(); + + for ( ; IDIter != IDIterEnd; ++IDIter ) + { + // Check to see if a request for this object has already been made. + if ( mPendingObjectQuota.find( *IDIter ) == mPendingObjectQuota.end() ) + { + mPendingObjectQuota.insert( *IDIter ); + objectList[objectIndex++] = *IDIter; + } + } + + mUpdateObjectQuota.clear(); + + //Post results + if ( objectList.size() > 0 ) + { + LLSD dataToPost = LLSD::emptyMap(); + dataToPost["object_ids"] = objectList; + LLHTTPClient::post( url, dataToPost, new LLAccountingQuotaResponder( objectList )); + } + } + else + { + //url was empty - warn & continue + llwarns<<"Supplied url is empty "<<llendl; + mUpdateObjectQuota.clear(); + mPendingObjectQuota.clear(); + } +} +//=============================================================================== +void LLAccountingQuotaManager::updateObjectCost( const LLUUID& objectID ) +{ + mUpdateObjectQuota.insert( objectID ); +} +//=============================================================================== +void LLAccountingQuotaManager::removePendingObjectQuota( const LLUUID& objectID ) +{ + mPendingObjectQuota.erase( objectID ); +} +//=============================================================================== diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 29b50761d8..5f89d11391 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -889,9 +889,9 @@ void LLBumpImageList::destroyGL() void LLBumpImageList::restoreGL() { - if(!gTextureList.isInitialized())
- {
- return ;
+ if(!gTextureList.isInitialized()) + { + return ; } LLStandardBumpmap::restoreGL(); diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index d1bff9f423..83844048d1 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -1,807 +1,807 @@ -/**
- * @file llfeaturemanager.cpp
- * @brief LLFeatureManager class implementation
- *
- * $LicenseInfo:firstyear=2003&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 <iostream>
-#include <fstream>
-
-#include <boost/regex.hpp>
-
-#include "llfeaturemanager.h"
-#include "lldir.h"
-
-#include "llsys.h"
-#include "llgl.h"
-#include "llsecondlifeurls.h"
-
-#include "llappviewer.h"
-#include "llhttpclient.h"
-#include "llnotificationsutil.h"
-#include "llviewercontrol.h"
-#include "llworld.h"
-#include "lldrawpoolterrain.h"
-#include "llviewertexturelist.h"
-#include "llversioninfo.h"
-#include "llwindow.h"
-#include "llui.h"
-#include "llcontrol.h"
-#include "llboost.h"
-#include "llweb.h"
-
-#if LL_WINDOWS
-#include "lldxhardware.h"
-#endif
-
-
-#if LL_DARWIN
-const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt";
-const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt";
-#elif LL_LINUX
-const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt";
-const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt";
-#elif LL_SOLARIS
-const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt";
-const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt";
-#else
-const char FEATURE_TABLE_FILENAME[] = "featuretable%s.txt";
-const char FEATURE_TABLE_VER_FILENAME[] = "featuretable%s.%s.txt";
-#endif
-
-const char GPU_TABLE_FILENAME[] = "gpu_table.txt";
-const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt";
-
-LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level)
- : mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level)
-{
-}
-
-LLFeatureList::LLFeatureList(const std::string& name)
- : mName(name)
-{
-}
-
-LLFeatureList::~LLFeatureList()
-{
-}
-
-void LLFeatureList::addFeature(const std::string& name, const BOOL available, const F32 level)
-{
- if (mFeatures.count(name))
- {
- LL_WARNS("RenderInit") << "LLFeatureList::Attempting to add preexisting feature " << name << LL_ENDL;
- }
-
- LLFeatureInfo fi(name, available, level);
- mFeatures[name] = fi;
-}
-
-BOOL LLFeatureList::isFeatureAvailable(const std::string& name)
-{
- if (mFeatures.count(name))
- {
- return mFeatures[name].mAvailable;
- }
-
- LL_WARNS("RenderInit") << "Feature " << name << " not on feature list!" << LL_ENDL;
-
- // changing this to TRUE so you have to explicitly disable
- // something for it to be disabled
- return TRUE;
-}
-
-F32 LLFeatureList::getRecommendedValue(const std::string& name)
-{
- if (mFeatures.count(name) && isFeatureAvailable(name))
- {
- return mFeatures[name].mRecommendedLevel;
- }
-
- LL_WARNS("RenderInit") << "Feature " << name << " not on feature list or not available!" << LL_ENDL;
- return 0;
-}
-
-BOOL LLFeatureList::maskList(LLFeatureList &mask)
-{
- //llinfos << "Masking with " << mask.mName << llendl;
- //
- // Lookup the specified feature mask, and overlay it on top of the
- // current feature mask.
- //
-
- LLFeatureInfo mask_fi;
-
- feature_map_t::iterator feature_it;
- for (feature_it = mask.mFeatures.begin(); feature_it != mask.mFeatures.end(); ++feature_it)
- {
- mask_fi = feature_it->second;
- //
- // Look for the corresponding feature
- //
- if (!mFeatures.count(mask_fi.mName))
- {
- LL_WARNS("RenderInit") << "Feature " << mask_fi.mName << " in mask not in top level!" << LL_ENDL;
- continue;
- }
-
- LLFeatureInfo &cur_fi = mFeatures[mask_fi.mName];
- if (mask_fi.mAvailable && !cur_fi.mAvailable)
- {
- LL_WARNS("RenderInit") << "Mask attempting to reenabling disabled feature, ignoring " << cur_fi.mName << LL_ENDL;
- continue;
- }
- cur_fi.mAvailable = mask_fi.mAvailable;
- cur_fi.mRecommendedLevel = llmin(cur_fi.mRecommendedLevel, mask_fi.mRecommendedLevel);
- LL_DEBUGS("RenderInit") << "Feature mask " << mask.mName
- << " Feature " << mask_fi.mName
- << " Mask: " << mask_fi.mRecommendedLevel
- << " Now: " << cur_fi.mRecommendedLevel << LL_ENDL;
- }
-
- LL_DEBUGS("RenderInit") << "After applying mask " << mask.mName << std::endl;
- // Will conditionally call dump only if the above message will be logged, thanks
- // to it being wrapped by the LL_DEBUGS and LL_ENDL macros.
- dump();
- LL_CONT << LL_ENDL;
-
- return TRUE;
-}
-
-void LLFeatureList::dump()
-{
- LL_DEBUGS("RenderInit") << "Feature list: " << mName << LL_ENDL;
- LL_DEBUGS("RenderInit") << "--------------" << LL_ENDL;
-
- LLFeatureInfo fi;
- feature_map_t::iterator feature_it;
- for (feature_it = mFeatures.begin(); feature_it != mFeatures.end(); ++feature_it)
- {
- fi = feature_it->second;
- LL_DEBUGS("RenderInit") << fi.mName << "\t\t" << fi.mAvailable << ":" << fi.mRecommendedLevel << LL_ENDL;
- }
- LL_DEBUGS("RenderInit") << LL_ENDL;
-}
-
-LLFeatureList *LLFeatureManager::findMask(const std::string& name)
-{
- if (mMaskList.count(name))
- {
- return mMaskList[name];
- }
-
- return NULL;
-}
-
-BOOL LLFeatureManager::maskFeatures(const std::string& name)
-{
- LLFeatureList *maskp = findMask(name);
- if (!maskp)
- {
- LL_DEBUGS("RenderInit") << "Unknown feature mask " << name << LL_ENDL;
- return FALSE;
- }
- LL_INFOS("RenderInit") << "Applying GPU Feature list: " << name << LL_ENDL;
- return maskList(*maskp);
-}
-
-BOOL LLFeatureManager::loadFeatureTables()
-{
- // *TODO - if I or anyone else adds something else to the skipped list
- // make this data driven. Put it in the feature table and parse it
- // correctly
- mSkippedFeatures.insert("RenderAnisotropic");
- mSkippedFeatures.insert("RenderGamma");
- mSkippedFeatures.insert("RenderVBOEnable");
- mSkippedFeatures.insert("RenderFogRatio");
-
- // first table is install with app
- std::string app_path = gDirUtilp->getAppRODataDir();
- app_path += gDirUtilp->getDirDelimiter();
-
- std::string filename;
- std::string http_filename;
-#if LL_WINDOWS
- std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
- if (os_string.find("Microsoft Windows XP") == 0)
- {
- filename = llformat(FEATURE_TABLE_FILENAME, "_xp");
- http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "_xp", LLVersionInfo::getVersion().c_str());
- }
- else
- {
- filename = llformat(FEATURE_TABLE_FILENAME, "");
- http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "", LLVersionInfo::getVersion().c_str());
- }
-#else
- filename = FEATURE_TABLE_FILENAME;
- http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
-#endif
-
- app_path += filename;
-
-
- // second table is downloaded with HTTP
- std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
-
- // use HTTP table if it exists
- std::string path;
- if (gDirUtilp->fileExists(http_path))
- {
- path = http_path;
- }
- else
- {
- path = app_path;
- }
-
-
- return parseFeatureTable(path);
-}
-
-
-BOOL LLFeatureManager::parseFeatureTable(std::string filename)
-{
- llinfos << "Looking for feature table in " << filename << llendl;
-
- llifstream file;
- std::string name;
- U32 version;
-
- file.open(filename); /*Flawfinder: ignore*/
-
- if (!file)
- {
- LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL;
- return FALSE;
- }
-
- // Check file version
- file >> name;
- file >> version;
- if (name != "version")
- {
- LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL;
- return FALSE;
- }
-
- mTableVersion = version;
-
- LLFeatureList *flp = NULL;
- while (file >> name)
- {
- char buffer[MAX_STRING]; /*Flawfinder: ignore*/
-
- if (name.substr(0,2) == "//")
- {
- // This is a comment.
- file.getline(buffer, MAX_STRING);
- continue;
- }
-
- if (name == "list")
- {
- if (flp)
- {
- //flp->dump();
- }
- // It's a new mask, create it.
- file >> name;
- if (mMaskList.count(name))
- {
- LL_ERRS("RenderInit") << "Overriding mask " << name << ", this is invalid!" << LL_ENDL;
- }
-
- flp = new LLFeatureList(name);
- mMaskList[name] = flp;
- }
- else
- {
- if (!flp)
- {
- LL_ERRS("RenderInit") << "Specified parameter before <list> keyword!" << LL_ENDL;
- return FALSE;
- }
- S32 available;
- F32 recommended;
- file >> available >> recommended;
- flp->addFeature(name, available, recommended);
- }
- }
- file.close();
-
- return TRUE;
-}
-
-void LLFeatureManager::loadGPUClass()
-{
- // defaults
- mGPUClass = GPU_CLASS_UNKNOWN;
- mGPUString = gGLManager.getRawGLString();
- mGPUSupported = FALSE;
-
- // first table is in the app dir
- std::string app_path = gDirUtilp->getAppRODataDir();
- app_path += gDirUtilp->getDirDelimiter();
- app_path += GPU_TABLE_FILENAME;
-
- // second table is downloaded with HTTP
- std::string http_filename = llformat(GPU_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
- std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
-
- // use HTTP table if it exists
- std::string path;
- if (gDirUtilp->fileExists(http_path))
- {
- path = http_path;
- }
- else
- {
- path = app_path;
- }
-
- parseGPUTable(path);
-}
-
-
-void LLFeatureManager::parseGPUTable(std::string filename)
-{
- llifstream file;
-
- file.open(filename);
-
- if (!file)
- {
- LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL;
- return;
- }
-
- std::string rawRenderer = gGLManager.getRawGLString();
- std::string renderer = rawRenderer;
- for (std::string::iterator i = renderer.begin(); i != renderer.end(); ++i)
- {
- *i = tolower(*i);
- }
-
- bool gpuFound;
- U32 lineNumber;
- for (gpuFound = false, lineNumber = 0; !gpuFound && !file.eof(); lineNumber++)
- {
- char buffer[MAX_STRING]; /*Flawfinder: ignore*/
- buffer[0] = 0;
-
- file.getline(buffer, MAX_STRING);
-
- if (strlen(buffer) >= 2 && /*Flawfinder: ignore*/
- buffer[0] == '/' &&
- buffer[1] == '/')
- {
- // This is a comment.
- continue;
- }
-
- if (strlen(buffer) == 0) /*Flawfinder: ignore*/
- {
- // This is a blank line
- continue;
- }
-
- // setup the tokenizer
- std::string buf(buffer);
- std::string cls, label, expr, supported;
- boost_tokenizer tokens(buf, boost::char_separator<char>("\t\n"));
- boost_tokenizer::iterator token_iter = tokens.begin();
-
- // grab the label, pseudo regular expression, and class
- if(token_iter != tokens.end())
- {
- label = *token_iter++;
- }
- if(token_iter != tokens.end())
- {
- expr = *token_iter++;
- }
- if(token_iter != tokens.end())
- {
- cls = *token_iter++;
- }
- if(token_iter != tokens.end())
- {
- supported = *token_iter++;
- }
-
- if (label.empty() || expr.empty() || cls.empty() || supported.empty())
- {
- LL_WARNS("RenderInit") << "invald gpu_table.txt:" << lineNumber << ": '" << buffer << "'" << LL_ENDL;
- continue;
- }
-
- for (U32 i = 0; i < expr.length(); i++) /*Flawfinder: ignore*/
- {
- expr[i] = tolower(expr[i]);
- }
-
- // run the regular expression against the renderer
- boost::regex re(expr.c_str());
- if(boost::regex_search(renderer, re))
- {
- // if we found it, stop!
- gpuFound = true;
- mGPUString = label;
- mGPUClass = (EGPUClass) strtol(cls.c_str(), NULL, 10);
- mGPUSupported = (BOOL) strtol(supported.c_str(), NULL, 10);
- }
- }
- file.close();
-
- if ( gpuFound )
- {
- LL_INFOS("RenderInit") << "GPU '" << rawRenderer << "' recognized as '" << mGPUString << "'" << LL_ENDL;
- if (!mGPUSupported)
- {
- LL_INFOS("RenderInit") << "GPU '" << mGPUString << "' is not supported." << LL_ENDL;
- }
- }
- else
- {
- LL_WARNS("RenderInit") << "GPU '" << rawRenderer << "' not recognized" << LL_ENDL;
- }
-}
-
-// responder saves table into file
-class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
-{
-public:
-
- LLHTTPFeatureTableResponder(std::string filename) :
- mFilename(filename)
- {
- }
-
-
- virtual void completedRaw(U32 status, const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- if (isGoodStatus(status))
- {
- // write to file
-
- llinfos << "writing feature table to " << mFilename << llendl;
-
- S32 file_size = buffer->countAfter(channels.in(), NULL);
- if (file_size > 0)
- {
- // read from buffer
- U8* copy_buffer = new U8[file_size];
- buffer->readAfter(channels.in(), NULL, copy_buffer, file_size);
-
- // write to file
- LLAPRFile out(mFilename, LL_APR_WB);
- out.write(copy_buffer, file_size);
- out.close();
- }
- }
-
- }
-
-private:
- std::string mFilename;
-};
-
-void fetch_feature_table(std::string table)
-{
- const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable");
-
-#if LL_WINDOWS
- std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
- std::string filename;
- if (os_string.find("Microsoft Windows XP") == 0)
- {
- filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str());
- }
- else
- {
- filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str());
- }
-#else
- const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str());
-#endif
-
- const std::string url = base + "/" + filename;
-
- const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
-
- llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl;
-
- LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path));
-}
-
-void fetch_gpu_table(std::string table)
-{
- const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable");
-
- const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str());
-
- const std::string url = base + "/" + filename;
-
- const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
-
- llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl;
-
- LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path));
-}
-
-// fetch table(s) from a website (S3)
-void LLFeatureManager::fetchHTTPTables()
-{
- fetch_feature_table(FEATURE_TABLE_VER_FILENAME);
- fetch_gpu_table(GPU_TABLE_VER_FILENAME);
-}
-
-
-void LLFeatureManager::cleanupFeatureTables()
-{
- std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer());
- mMaskList.clear();
-}
-
-void LLFeatureManager::init()
-{
- // load the tables
- loadFeatureTables();
-
- // get the gpu class
- loadGPUClass();
-
- // apply the base masks, so we know if anything is disabled
- applyBaseMasks();
-}
-
-void LLFeatureManager::applyRecommendedSettings()
-{
- // apply saved settings
- // cap the level at 2 (high)
- S32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_2));
-
- llinfos << "Applying Recommended Features" << llendl;
-
- setGraphicsLevel(level, false);
- gSavedSettings.setU32("RenderQualityPerformance", level);
-
- // now apply the tweaks to draw distance
- // these are double negatives, because feature masks only work by
- // downgrading values, so i needed to make a true value go to false
- // for certain cards, thus the awkward name, "Disregard..."
- if(!gSavedSettings.getBOOL("Disregard96DefaultDrawDistance"))
- {
- gSavedSettings.setF32("RenderFarClip", 96.0f);
- }
- else if(!gSavedSettings.getBOOL("Disregard128DefaultDrawDistance"))
- {
- gSavedSettings.setF32("RenderFarClip", 128.0f);
- }
-}
-
-void LLFeatureManager::applyFeatures(bool skipFeatures)
-{
- // see featuretable.txt / featuretable_linux.txt / featuretable_mac.txt
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- dump();
-#endif
-
- // scroll through all of these and set their corresponding control value
- for(feature_map_t::iterator mIt = mFeatures.begin();
- mIt != mFeatures.end();
- ++mIt)
- {
- // skip features you want to skip
- // do this for when you don't want to change certain settings
- if(skipFeatures)
- {
- if(mSkippedFeatures.find(mIt->first) != mSkippedFeatures.end())
- {
- continue;
- }
- }
-
- // get the control setting
- LLControlVariable* ctrl = gSavedSettings.getControl(mIt->first);
- if(ctrl == NULL)
- {
- llwarns << "AHHH! Control setting " << mIt->first << " does not exist!" << llendl;
- continue;
- }
-
- // handle all the different types
- if(ctrl->isType(TYPE_BOOLEAN))
- {
- gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first));
- }
- else if (ctrl->isType(TYPE_S32))
- {
- gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first));
- }
- else if (ctrl->isType(TYPE_U32))
- {
- gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first));
- }
- else if (ctrl->isType(TYPE_F32))
- {
- gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first));
- }
- else
- {
- llwarns << "AHHH! Control variable is not a numeric type!" << llendl;
- }
- }
-}
-
-void LLFeatureManager::setGraphicsLevel(S32 level, bool skipFeatures)
-{
- applyBaseMasks();
-
- switch (level)
- {
- case 0:
- maskFeatures("Low");
- break;
- case 1:
- maskFeatures("Mid");
- break;
- case 2:
- maskFeatures("High");
- break;
- case 3:
- maskFeatures("Ultra");
- break;
- default:
- maskFeatures("Low");
- break;
- }
-
- applyFeatures(skipFeatures);
-}
-
-void LLFeatureManager::applyBaseMasks()
-{
- // reapply masks
- mFeatures.clear();
-
- LLFeatureList* maskp = findMask("all");
- if(maskp == NULL)
- {
- LL_WARNS("RenderInit") << "AHH! No \"all\" in feature table!" << LL_ENDL;
- return;
- }
-
- mFeatures = maskp->getFeatures();
-
- // mask class
- if (mGPUClass >= 0 && mGPUClass < 4)
- {
- const char* class_table[] =
- {
- "Class0",
- "Class1",
- "Class2",
- "Class3"
- };
-
- LL_INFOS("RenderInit") << "Setting GPU Class to " << class_table[mGPUClass] << LL_ENDL;
- maskFeatures(class_table[mGPUClass]);
- }
- else
- {
- LL_INFOS("RenderInit") << "Setting GPU Class to Unknown" << LL_ENDL;
- maskFeatures("Unknown");
- }
-
- // now all those wacky ones
- if (!gGLManager.mHasFragmentShader)
- {
- maskFeatures("NoPixelShaders");
- }
- if (!gGLManager.mHasVertexShader)
- {
- maskFeatures("NoVertexShaders");
- }
- if (gGLManager.mIsNVIDIA)
- {
- maskFeatures("NVIDIA");
- }
- if (gGLManager.mIsGF2or4MX)
- {
- maskFeatures("GeForce2");
- }
- if (gGLManager.mIsATI)
- {
- maskFeatures("ATI");
- }
- if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256)
- {
- maskFeatures("ATIVramLT256");
- }
- if (gGLManager.mATIOldDriver)
- {
- maskFeatures("ATIOldDriver");
- }
- if (gGLManager.mIsGFFX)
- {
- maskFeatures("GeForceFX");
- }
- if (gGLManager.mIsIntel)
- {
- maskFeatures("Intel");
- }
- if (gGLManager.mGLVersion < 1.5f)
- {
- maskFeatures("OpenGLPre15");
- }
- if (gGLManager.mGLVersion < 3.f)
- {
- maskFeatures("OpenGLPre30");
- }
- if (gGLManager.mNumTextureImageUnits <= 8)
- {
- maskFeatures("TexUnit8orLess");
- }
-
- // now mask by gpu string
- // Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces
- std::string gpustr = mGPUString;
- for (std::string::iterator iter = gpustr.begin(); iter != gpustr.end(); ++iter)
- {
- if (*iter == ' ')
- {
- *iter = '_';
- }
- }
-
- //llinfos << "Masking features from gpu table match: " << gpustr << llendl;
- maskFeatures(gpustr);
-
- // now mask cpu type ones
- if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024)
- {
- maskFeatures("RAM256MB");
- }
-
-#if LL_SOLARIS && defined(__sparc) // even low MHz SPARCs are fast
-#error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here?
- if (gSysCPU.getMHz() < 800)
-#else
- if (gSysCPU.getMHz() < 1100)
-#endif
- {
- maskFeatures("CPUSlow");
- }
-
- if (isSafe())
- {
- maskFeatures("safe");
- }
-}
+/** + * @file llfeaturemanager.cpp + * @brief LLFeatureManager class implementation + * + * $LicenseInfo:firstyear=2003&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 <iostream> +#include <fstream> + +#include <boost/regex.hpp> + +#include "llfeaturemanager.h" +#include "lldir.h" + +#include "llsys.h" +#include "llgl.h" +#include "llsecondlifeurls.h" + +#include "llappviewer.h" +#include "llhttpclient.h" +#include "llnotificationsutil.h" +#include "llviewercontrol.h" +#include "llworld.h" +#include "lldrawpoolterrain.h" +#include "llviewertexturelist.h" +#include "llversioninfo.h" +#include "llwindow.h" +#include "llui.h" +#include "llcontrol.h" +#include "llboost.h" +#include "llweb.h" + +#if LL_WINDOWS +#include "lldxhardware.h" +#endif + + +#if LL_DARWIN +const char FEATURE_TABLE_FILENAME[] = "featuretable_mac.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_mac.%s.txt"; +#elif LL_LINUX +const char FEATURE_TABLE_FILENAME[] = "featuretable_linux.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt"; +#elif LL_SOLARIS +const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt"; +#else +const char FEATURE_TABLE_FILENAME[] = "featuretable%s.txt"; +const char FEATURE_TABLE_VER_FILENAME[] = "featuretable%s.%s.txt"; +#endif + +const char GPU_TABLE_FILENAME[] = "gpu_table.txt"; +const char GPU_TABLE_VER_FILENAME[] = "gpu_table.%s.txt"; + +LLFeatureInfo::LLFeatureInfo(const std::string& name, const BOOL available, const F32 level) + : mValid(TRUE), mName(name), mAvailable(available), mRecommendedLevel(level) +{ +} + +LLFeatureList::LLFeatureList(const std::string& name) + : mName(name) +{ +} + +LLFeatureList::~LLFeatureList() +{ +} + +void LLFeatureList::addFeature(const std::string& name, const BOOL available, const F32 level) +{ + if (mFeatures.count(name)) + { + LL_WARNS("RenderInit") << "LLFeatureList::Attempting to add preexisting feature " << name << LL_ENDL; + } + + LLFeatureInfo fi(name, available, level); + mFeatures[name] = fi; +} + +BOOL LLFeatureList::isFeatureAvailable(const std::string& name) +{ + if (mFeatures.count(name)) + { + return mFeatures[name].mAvailable; + } + + LL_WARNS("RenderInit") << "Feature " << name << " not on feature list!" << LL_ENDL; + + // changing this to TRUE so you have to explicitly disable + // something for it to be disabled + return TRUE; +} + +F32 LLFeatureList::getRecommendedValue(const std::string& name) +{ + if (mFeatures.count(name) && isFeatureAvailable(name)) + { + return mFeatures[name].mRecommendedLevel; + } + + LL_WARNS("RenderInit") << "Feature " << name << " not on feature list or not available!" << LL_ENDL; + return 0; +} + +BOOL LLFeatureList::maskList(LLFeatureList &mask) +{ + //llinfos << "Masking with " << mask.mName << llendl; + // + // Lookup the specified feature mask, and overlay it on top of the + // current feature mask. + // + + LLFeatureInfo mask_fi; + + feature_map_t::iterator feature_it; + for (feature_it = mask.mFeatures.begin(); feature_it != mask.mFeatures.end(); ++feature_it) + { + mask_fi = feature_it->second; + // + // Look for the corresponding feature + // + if (!mFeatures.count(mask_fi.mName)) + { + LL_WARNS("RenderInit") << "Feature " << mask_fi.mName << " in mask not in top level!" << LL_ENDL; + continue; + } + + LLFeatureInfo &cur_fi = mFeatures[mask_fi.mName]; + if (mask_fi.mAvailable && !cur_fi.mAvailable) + { + LL_WARNS("RenderInit") << "Mask attempting to reenabling disabled feature, ignoring " << cur_fi.mName << LL_ENDL; + continue; + } + cur_fi.mAvailable = mask_fi.mAvailable; + cur_fi.mRecommendedLevel = llmin(cur_fi.mRecommendedLevel, mask_fi.mRecommendedLevel); + LL_DEBUGS("RenderInit") << "Feature mask " << mask.mName + << " Feature " << mask_fi.mName + << " Mask: " << mask_fi.mRecommendedLevel + << " Now: " << cur_fi.mRecommendedLevel << LL_ENDL; + } + + LL_DEBUGS("RenderInit") << "After applying mask " << mask.mName << std::endl; + // Will conditionally call dump only if the above message will be logged, thanks + // to it being wrapped by the LL_DEBUGS and LL_ENDL macros. + dump(); + LL_CONT << LL_ENDL; + + return TRUE; +} + +void LLFeatureList::dump() +{ + LL_DEBUGS("RenderInit") << "Feature list: " << mName << LL_ENDL; + LL_DEBUGS("RenderInit") << "--------------" << LL_ENDL; + + LLFeatureInfo fi; + feature_map_t::iterator feature_it; + for (feature_it = mFeatures.begin(); feature_it != mFeatures.end(); ++feature_it) + { + fi = feature_it->second; + LL_DEBUGS("RenderInit") << fi.mName << "\t\t" << fi.mAvailable << ":" << fi.mRecommendedLevel << LL_ENDL; + } + LL_DEBUGS("RenderInit") << LL_ENDL; +} + +LLFeatureList *LLFeatureManager::findMask(const std::string& name) +{ + if (mMaskList.count(name)) + { + return mMaskList[name]; + } + + return NULL; +} + +BOOL LLFeatureManager::maskFeatures(const std::string& name) +{ + LLFeatureList *maskp = findMask(name); + if (!maskp) + { + LL_DEBUGS("RenderInit") << "Unknown feature mask " << name << LL_ENDL; + return FALSE; + } + LL_INFOS("RenderInit") << "Applying GPU Feature list: " << name << LL_ENDL; + return maskList(*maskp); +} + +BOOL LLFeatureManager::loadFeatureTables() +{ + // *TODO - if I or anyone else adds something else to the skipped list + // make this data driven. Put it in the feature table and parse it + // correctly + mSkippedFeatures.insert("RenderAnisotropic"); + mSkippedFeatures.insert("RenderGamma"); + mSkippedFeatures.insert("RenderVBOEnable"); + mSkippedFeatures.insert("RenderFogRatio"); + + // first table is install with app + std::string app_path = gDirUtilp->getAppRODataDir(); + app_path += gDirUtilp->getDirDelimiter(); + + std::string filename; + std::string http_filename; +#if LL_WINDOWS + std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + if (os_string.find("Microsoft Windows XP") == 0) + { + filename = llformat(FEATURE_TABLE_FILENAME, "_xp"); + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "_xp", LLVersionInfo::getVersion().c_str()); + } + else + { + filename = llformat(FEATURE_TABLE_FILENAME, ""); + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "", LLVersionInfo::getVersion().c_str()); + } +#else + filename = FEATURE_TABLE_FILENAME; + http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); +#endif + + app_path += filename; + + + // second table is downloaded with HTTP + std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); + + // use HTTP table if it exists + std::string path; + if (gDirUtilp->fileExists(http_path)) + { + path = http_path; + } + else + { + path = app_path; + } + + + return parseFeatureTable(path); +} + + +BOOL LLFeatureManager::parseFeatureTable(std::string filename) +{ + llinfos << "Looking for feature table in " << filename << llendl; + + llifstream file; + std::string name; + U32 version; + + file.open(filename); /*Flawfinder: ignore*/ + + if (!file) + { + LL_WARNS("RenderInit") << "Unable to open feature table " << filename << LL_ENDL; + return FALSE; + } + + // Check file version + file >> name; + file >> version; + if (name != "version") + { + LL_WARNS("RenderInit") << filename << " does not appear to be a valid feature table!" << LL_ENDL; + return FALSE; + } + + mTableVersion = version; + + LLFeatureList *flp = NULL; + while (file >> name) + { + char buffer[MAX_STRING]; /*Flawfinder: ignore*/ + + if (name.substr(0,2) == "//") + { + // This is a comment. + file.getline(buffer, MAX_STRING); + continue; + } + + if (name == "list") + { + if (flp) + { + //flp->dump(); + } + // It's a new mask, create it. + file >> name; + if (mMaskList.count(name)) + { + LL_ERRS("RenderInit") << "Overriding mask " << name << ", this is invalid!" << LL_ENDL; + } + + flp = new LLFeatureList(name); + mMaskList[name] = flp; + } + else + { + if (!flp) + { + LL_ERRS("RenderInit") << "Specified parameter before <list> keyword!" << LL_ENDL; + return FALSE; + } + S32 available; + F32 recommended; + file >> available >> recommended; + flp->addFeature(name, available, recommended); + } + } + file.close(); + + return TRUE; +} + +void LLFeatureManager::loadGPUClass() +{ + // defaults + mGPUClass = GPU_CLASS_UNKNOWN; + mGPUString = gGLManager.getRawGLString(); + mGPUSupported = FALSE; + + // first table is in the app dir + std::string app_path = gDirUtilp->getAppRODataDir(); + app_path += gDirUtilp->getDirDelimiter(); + app_path += GPU_TABLE_FILENAME; + + // second table is downloaded with HTTP + std::string http_filename = llformat(GPU_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str()); + std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename); + + // use HTTP table if it exists + std::string path; + if (gDirUtilp->fileExists(http_path)) + { + path = http_path; + } + else + { + path = app_path; + } + + parseGPUTable(path); +} + + +void LLFeatureManager::parseGPUTable(std::string filename) +{ + llifstream file; + + file.open(filename); + + if (!file) + { + LL_WARNS("RenderInit") << "Unable to open GPU table: " << filename << "!" << LL_ENDL; + return; + } + + std::string rawRenderer = gGLManager.getRawGLString(); + std::string renderer = rawRenderer; + for (std::string::iterator i = renderer.begin(); i != renderer.end(); ++i) + { + *i = tolower(*i); + } + + bool gpuFound; + U32 lineNumber; + for (gpuFound = false, lineNumber = 0; !gpuFound && !file.eof(); lineNumber++) + { + char buffer[MAX_STRING]; /*Flawfinder: ignore*/ + buffer[0] = 0; + + file.getline(buffer, MAX_STRING); + + if (strlen(buffer) >= 2 && /*Flawfinder: ignore*/ + buffer[0] == '/' && + buffer[1] == '/') + { + // This is a comment. + continue; + } + + if (strlen(buffer) == 0) /*Flawfinder: ignore*/ + { + // This is a blank line + continue; + } + + // setup the tokenizer + std::string buf(buffer); + std::string cls, label, expr, supported; + boost_tokenizer tokens(buf, boost::char_separator<char>("\t\n")); + boost_tokenizer::iterator token_iter = tokens.begin(); + + // grab the label, pseudo regular expression, and class + if(token_iter != tokens.end()) + { + label = *token_iter++; + } + if(token_iter != tokens.end()) + { + expr = *token_iter++; + } + if(token_iter != tokens.end()) + { + cls = *token_iter++; + } + if(token_iter != tokens.end()) + { + supported = *token_iter++; + } + + if (label.empty() || expr.empty() || cls.empty() || supported.empty()) + { + LL_WARNS("RenderInit") << "invald gpu_table.txt:" << lineNumber << ": '" << buffer << "'" << LL_ENDL; + continue; + } + + for (U32 i = 0; i < expr.length(); i++) /*Flawfinder: ignore*/ + { + expr[i] = tolower(expr[i]); + } + + // run the regular expression against the renderer + boost::regex re(expr.c_str()); + if(boost::regex_search(renderer, re)) + { + // if we found it, stop! + gpuFound = true; + mGPUString = label; + mGPUClass = (EGPUClass) strtol(cls.c_str(), NULL, 10); + mGPUSupported = (BOOL) strtol(supported.c_str(), NULL, 10); + } + } + file.close(); + + if ( gpuFound ) + { + LL_INFOS("RenderInit") << "GPU '" << rawRenderer << "' recognized as '" << mGPUString << "'" << LL_ENDL; + if (!mGPUSupported) + { + LL_INFOS("RenderInit") << "GPU '" << mGPUString << "' is not supported." << LL_ENDL; + } + } + else + { + LL_WARNS("RenderInit") << "GPU '" << rawRenderer << "' not recognized" << LL_ENDL; + } +} + +// responder saves table into file +class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder +{ +public: + + LLHTTPFeatureTableResponder(std::string filename) : + mFilename(filename) + { + } + + + virtual void completedRaw(U32 status, const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + if (isGoodStatus(status)) + { + // write to file + + llinfos << "writing feature table to " << mFilename << llendl; + + S32 file_size = buffer->countAfter(channels.in(), NULL); + if (file_size > 0) + { + // read from buffer + U8* copy_buffer = new U8[file_size]; + buffer->readAfter(channels.in(), NULL, copy_buffer, file_size); + + // write to file + LLAPRFile out(mFilename, LL_APR_WB); + out.write(copy_buffer, file_size); + out.close(); + } + } + + } + +private: + std::string mFilename; +}; + +void fetch_feature_table(std::string table) +{ + const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); + +#if LL_WINDOWS + std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + std::string filename; + if (os_string.find("Microsoft Windows XP") == 0) + { + filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); + } + else + { + filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str()); + } +#else + const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); +#endif + + const std::string url = base + "/" + filename; + + const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); + + llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl; + + LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); +} + +void fetch_gpu_table(std::string table) +{ + const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); + + const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); + + const std::string url = base + "/" + filename; + + const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); + + llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl; + + LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); +} + +// fetch table(s) from a website (S3) +void LLFeatureManager::fetchHTTPTables() +{ + fetch_feature_table(FEATURE_TABLE_VER_FILENAME); + fetch_gpu_table(GPU_TABLE_VER_FILENAME); +} + + +void LLFeatureManager::cleanupFeatureTables() +{ + std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer()); + mMaskList.clear(); +} + +void LLFeatureManager::init() +{ + // load the tables + loadFeatureTables(); + + // get the gpu class + loadGPUClass(); + + // apply the base masks, so we know if anything is disabled + applyBaseMasks(); +} + +void LLFeatureManager::applyRecommendedSettings() +{ + // apply saved settings + // cap the level at 2 (high) + S32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_2)); + + llinfos << "Applying Recommended Features" << llendl; + + setGraphicsLevel(level, false); + gSavedSettings.setU32("RenderQualityPerformance", level); + + // now apply the tweaks to draw distance + // these are double negatives, because feature masks only work by + // downgrading values, so i needed to make a true value go to false + // for certain cards, thus the awkward name, "Disregard..." + if(!gSavedSettings.getBOOL("Disregard96DefaultDrawDistance")) + { + gSavedSettings.setF32("RenderFarClip", 96.0f); + } + else if(!gSavedSettings.getBOOL("Disregard128DefaultDrawDistance")) + { + gSavedSettings.setF32("RenderFarClip", 128.0f); + } +} + +void LLFeatureManager::applyFeatures(bool skipFeatures) +{ + // see featuretable.txt / featuretable_linux.txt / featuretable_mac.txt + +#ifndef LL_RELEASE_FOR_DOWNLOAD + dump(); +#endif + + // scroll through all of these and set their corresponding control value + for(feature_map_t::iterator mIt = mFeatures.begin(); + mIt != mFeatures.end(); + ++mIt) + { + // skip features you want to skip + // do this for when you don't want to change certain settings + if(skipFeatures) + { + if(mSkippedFeatures.find(mIt->first) != mSkippedFeatures.end()) + { + continue; + } + } + + // get the control setting + LLControlVariable* ctrl = gSavedSettings.getControl(mIt->first); + if(ctrl == NULL) + { + llwarns << "AHHH! Control setting " << mIt->first << " does not exist!" << llendl; + continue; + } + + // handle all the different types + if(ctrl->isType(TYPE_BOOLEAN)) + { + gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first)); + } + else if (ctrl->isType(TYPE_S32)) + { + gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first)); + } + else if (ctrl->isType(TYPE_U32)) + { + gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first)); + } + else if (ctrl->isType(TYPE_F32)) + { + gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first)); + } + else + { + llwarns << "AHHH! Control variable is not a numeric type!" << llendl; + } + } +} + +void LLFeatureManager::setGraphicsLevel(S32 level, bool skipFeatures) +{ + applyBaseMasks(); + + switch (level) + { + case 0: + maskFeatures("Low"); + break; + case 1: + maskFeatures("Mid"); + break; + case 2: + maskFeatures("High"); + break; + case 3: + maskFeatures("Ultra"); + break; + default: + maskFeatures("Low"); + break; + } + + applyFeatures(skipFeatures); +} + +void LLFeatureManager::applyBaseMasks() +{ + // reapply masks + mFeatures.clear(); + + LLFeatureList* maskp = findMask("all"); + if(maskp == NULL) + { + LL_WARNS("RenderInit") << "AHH! No \"all\" in feature table!" << LL_ENDL; + return; + } + + mFeatures = maskp->getFeatures(); + + // mask class + if (mGPUClass >= 0 && mGPUClass < 4) + { + const char* class_table[] = + { + "Class0", + "Class1", + "Class2", + "Class3" + }; + + LL_INFOS("RenderInit") << "Setting GPU Class to " << class_table[mGPUClass] << LL_ENDL; + maskFeatures(class_table[mGPUClass]); + } + else + { + LL_INFOS("RenderInit") << "Setting GPU Class to Unknown" << LL_ENDL; + maskFeatures("Unknown"); + } + + // now all those wacky ones + if (!gGLManager.mHasFragmentShader) + { + maskFeatures("NoPixelShaders"); + } + if (!gGLManager.mHasVertexShader) + { + maskFeatures("NoVertexShaders"); + } + if (gGLManager.mIsNVIDIA) + { + maskFeatures("NVIDIA"); + } + if (gGLManager.mIsGF2or4MX) + { + maskFeatures("GeForce2"); + } + if (gGLManager.mIsATI) + { + maskFeatures("ATI"); + } + if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256) + { + maskFeatures("ATIVramLT256"); + } + if (gGLManager.mATIOldDriver) + { + maskFeatures("ATIOldDriver"); + } + if (gGLManager.mIsGFFX) + { + maskFeatures("GeForceFX"); + } + if (gGLManager.mIsIntel) + { + maskFeatures("Intel"); + } + if (gGLManager.mGLVersion < 1.5f) + { + maskFeatures("OpenGLPre15"); + } + if (gGLManager.mGLVersion < 3.f) + { + maskFeatures("OpenGLPre30"); + } + if (gGLManager.mNumTextureImageUnits <= 8) + { + maskFeatures("TexUnit8orLess"); + } + + // now mask by gpu string + // Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces + std::string gpustr = mGPUString; + for (std::string::iterator iter = gpustr.begin(); iter != gpustr.end(); ++iter) + { + if (*iter == ' ') + { + *iter = '_'; + } + } + + //llinfos << "Masking features from gpu table match: " << gpustr << llendl; + maskFeatures(gpustr); + + // now mask cpu type ones + if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024) + { + maskFeatures("RAM256MB"); + } + +#if LL_SOLARIS && defined(__sparc) // even low MHz SPARCs are fast +#error The 800 is hinky. Would something like a LL_MIN_MHZ make more sense here? + if (gSysCPU.getMHz() < 800) +#else + if (gSysCPU.getMHz() < 1100) +#endif + { + maskFeatures("CPUSlow"); + } + + if (isSafe()) + { + maskFeatures("safe"); + } +} diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 50b19a4221..610142b5a9 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -461,15 +461,15 @@ void LLFloaterBuyLandUI::updateParcelInfo() if (!authorizedBuyer.isNull() && buyer != authorizedBuyer) { - // Maybe the parcel is set for sale to a group we are in.
- bool authorized_group =
- gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_DEED)
- && gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_SET_SALE_INFO);
-
- if (!authorized_group)
- {
- mCannotBuyReason = getString("set_to_sell_to_other");
- return;
+ // Maybe the parcel is set for sale to a group we are in. + bool authorized_group = + gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_DEED) + && gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_SET_SALE_INFO); + + if (!authorized_group) + { + mCannotBuyReason = getString("set_to_sell_to_other"); + return; } } } diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 74f48907d2..34a92cd0ac 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1,1999 +1,1999 @@ -/**
- * @file llpanelobject.cpp
- * @brief Object editing (position, scale, etc.) in the tools floater
- *
- * $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"
-
-// file include
-#include "llpanelobject.h"
-
-// linden library includes
-#include "lleconomy.h"
-#include "llerror.h"
-#include "llfontgl.h"
-#include "llpermissionsflags.h"
-#include "llstring.h"
-#include "llvolume.h"
-#include "m3math.h"
-
-// project includes
-#include "llagent.h"
-#include "llbutton.h"
-#include "llcheckboxctrl.h"
-#include "llcolorswatch.h"
-#include "llcombobox.h"
-#include "llfocusmgr.h"
-#include "llmanipscale.h"
-#include "llpreviewscript.h"
-#include "llresmgr.h"
-#include "llselectmgr.h"
-#include "llspinctrl.h"
-#include "lltexturectrl.h"
-#include "lltextbox.h"
-#include "lltool.h"
-#include "lltoolcomp.h"
-#include "lltoolmgr.h"
-#include "llui.h"
-#include "llviewerobject.h"
-#include "llviewerregion.h"
-#include "llviewerwindow.h"
-#include "llvovolume.h"
-#include "llworld.h"
-#include "pipeline.h"
-#include "llviewercontrol.h"
-#include "lluictrlfactory.h"
-//#include "llfirstuse.h"
-
-#include "lldrawpool.h"
-
-//
-// Constants
-//
-enum {
- MI_BOX,
- MI_CYLINDER,
- MI_PRISM,
- MI_SPHERE,
- MI_TORUS,
- MI_TUBE,
- MI_RING,
- MI_SCULPT,
- MI_NONE,
- MI_VOLUME_COUNT
-};
-
-enum {
- MI_HOLE_SAME,
- MI_HOLE_CIRCLE,
- MI_HOLE_SQUARE,
- MI_HOLE_TRIANGLE,
- MI_HOLE_COUNT
-};
-
-//static const std::string LEGACY_FULLBRIGHT_DESC =LLTrans::getString("Fullbright");
-
-BOOL LLPanelObject::postBuild()
-{
- setMouseOpaque(FALSE);
-
- //--------------------------------------------------------
- // Top
- //--------------------------------------------------------
-
- // Lock checkbox
- mCheckLock = getChild<LLCheckBoxCtrl>("checkbox locked");
- childSetCommitCallback("checkbox locked",onCommitLock,this);
-
- // Physical checkbox
- mCheckPhysics = getChild<LLCheckBoxCtrl>("Physical Checkbox Ctrl");
- childSetCommitCallback("Physical Checkbox Ctrl",onCommitPhysics,this);
-
- // Temporary checkbox
- mCheckTemporary = getChild<LLCheckBoxCtrl>("Temporary Checkbox Ctrl");
- childSetCommitCallback("Temporary Checkbox Ctrl",onCommitTemporary,this);
-
- // Phantom checkbox
- mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl");
- childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this);
-
-
- // Position
- mLabelPosition = getChild<LLTextBox>("label position");
- mCtrlPosX = getChild<LLSpinCtrl>("Pos X");
- childSetCommitCallback("Pos X",onCommitPosition,this);
- mCtrlPosY = getChild<LLSpinCtrl>("Pos Y");
- childSetCommitCallback("Pos Y",onCommitPosition,this);
- mCtrlPosZ = getChild<LLSpinCtrl>("Pos Z");
- childSetCommitCallback("Pos Z",onCommitPosition,this);
-
- // Scale
- mLabelSize = getChild<LLTextBox>("label size");
- mCtrlScaleX = getChild<LLSpinCtrl>("Scale X");
- childSetCommitCallback("Scale X",onCommitScale,this);
-
- // Scale Y
- mCtrlScaleY = getChild<LLSpinCtrl>("Scale Y");
- childSetCommitCallback("Scale Y",onCommitScale,this);
-
- // Scale Z
- mCtrlScaleZ = getChild<LLSpinCtrl>("Scale Z");
- childSetCommitCallback("Scale Z",onCommitScale,this);
-
- // Rotation
- mLabelRotation = getChild<LLTextBox>("label rotation");
- mCtrlRotX = getChild<LLSpinCtrl>("Rot X");
- childSetCommitCallback("Rot X",onCommitRotation,this);
- mCtrlRotY = getChild<LLSpinCtrl>("Rot Y");
- childSetCommitCallback("Rot Y",onCommitRotation,this);
- mCtrlRotZ = getChild<LLSpinCtrl>("Rot Z");
- childSetCommitCallback("Rot Z",onCommitRotation,this);
-
- //--------------------------------------------------------
-
- // Base Type
- mComboBaseType = getChild<LLComboBox>("comboBaseType");
- childSetCommitCallback("comboBaseType",onCommitParametric,this);
-
- // Cut
- mLabelCut = getChild<LLTextBox>("text cut");
- mSpinCutBegin = getChild<LLSpinCtrl>("cut begin");
- childSetCommitCallback("cut begin",onCommitParametric,this);
- mSpinCutBegin->setValidateBeforeCommit( precommitValidate );
- mSpinCutEnd = getChild<LLSpinCtrl>("cut end");
- childSetCommitCallback("cut end",onCommitParametric,this);
- mSpinCutEnd->setValidateBeforeCommit( &precommitValidate );
-
- // Hollow / Skew
- mLabelHollow = getChild<LLTextBox>("text hollow");
- mLabelSkew = getChild<LLTextBox>("text skew");
- mSpinHollow = getChild<LLSpinCtrl>("Scale 1");
- childSetCommitCallback("Scale 1",onCommitParametric,this);
- mSpinHollow->setValidateBeforeCommit( &precommitValidate );
- mSpinSkew = getChild<LLSpinCtrl>("Skew");
- childSetCommitCallback("Skew",onCommitParametric,this);
- mSpinSkew->setValidateBeforeCommit( &precommitValidate );
- mLabelHoleType = getChild<LLTextBox>("Hollow Shape");
-
- // Hole Type
- mComboHoleType = getChild<LLComboBox>("hole");
- childSetCommitCallback("hole",onCommitParametric,this);
-
- // Twist
- mLabelTwist = getChild<LLTextBox>("text twist");
- mSpinTwistBegin = getChild<LLSpinCtrl>("Twist Begin");
- childSetCommitCallback("Twist Begin",onCommitParametric,this);
- mSpinTwistBegin->setValidateBeforeCommit( precommitValidate );
- mSpinTwist = getChild<LLSpinCtrl>("Twist End");
- childSetCommitCallback("Twist End",onCommitParametric,this);
- mSpinTwist->setValidateBeforeCommit( &precommitValidate );
-
- // Scale
- mSpinScaleX = getChild<LLSpinCtrl>("Taper Scale X");
- childSetCommitCallback("Taper Scale X",onCommitParametric,this);
- mSpinScaleX->setValidateBeforeCommit( &precommitValidate );
- mSpinScaleY = getChild<LLSpinCtrl>("Taper Scale Y");
- childSetCommitCallback("Taper Scale Y",onCommitParametric,this);
- mSpinScaleY->setValidateBeforeCommit( &precommitValidate );
-
- // Shear
- mLabelShear = getChild<LLTextBox>("text topshear");
- mSpinShearX = getChild<LLSpinCtrl>("Shear X");
- childSetCommitCallback("Shear X",onCommitParametric,this);
- mSpinShearX->setValidateBeforeCommit( &precommitValidate );
- mSpinShearY = getChild<LLSpinCtrl>("Shear Y");
- childSetCommitCallback("Shear Y",onCommitParametric,this);
- mSpinShearY->setValidateBeforeCommit( &precommitValidate );
-
- // Path / Profile
- mCtrlPathBegin = getChild<LLSpinCtrl>("Path Limit Begin");
- childSetCommitCallback("Path Limit Begin",onCommitParametric,this);
- mCtrlPathBegin->setValidateBeforeCommit( &precommitValidate );
- mCtrlPathEnd = getChild<LLSpinCtrl>("Path Limit End");
- childSetCommitCallback("Path Limit End",onCommitParametric,this);
- mCtrlPathEnd->setValidateBeforeCommit( &precommitValidate );
-
- // Taper
- mLabelTaper = getChild<LLTextBox>("text taper2");
- mSpinTaperX = getChild<LLSpinCtrl>("Taper X");
- childSetCommitCallback("Taper X",onCommitParametric,this);
- mSpinTaperX->setValidateBeforeCommit( precommitValidate );
- mSpinTaperY = getChild<LLSpinCtrl>("Taper Y");
- childSetCommitCallback("Taper Y",onCommitParametric,this);
- mSpinTaperY->setValidateBeforeCommit( precommitValidate );
-
- // Radius Offset / Revolutions
- mLabelRadiusOffset = getChild<LLTextBox>("text radius delta");
- mLabelRevolutions = getChild<LLTextBox>("text revolutions");
- mSpinRadiusOffset = getChild<LLSpinCtrl>("Radius Offset");
- childSetCommitCallback("Radius Offset",onCommitParametric,this);
- mSpinRadiusOffset->setValidateBeforeCommit( &precommitValidate );
- mSpinRevolutions = getChild<LLSpinCtrl>("Revolutions");
- childSetCommitCallback("Revolutions",onCommitParametric,this);
- mSpinRevolutions->setValidateBeforeCommit( &precommitValidate );
-
- // Sculpt
- mCtrlSculptTexture = getChild<LLTextureCtrl>("sculpt texture control");
- if (mCtrlSculptTexture)
- {
- mCtrlSculptTexture->setDefaultImageAssetID(LLUUID(SCULPT_DEFAULT_TEXTURE));
- mCtrlSculptTexture->setCommitCallback( boost::bind(&LLPanelObject::onCommitSculpt, this, _2 ));
- mCtrlSculptTexture->setOnCancelCallback( boost::bind(&LLPanelObject::onCancelSculpt, this, _2 ));
- mCtrlSculptTexture->setOnSelectCallback( boost::bind(&LLPanelObject::onSelectSculpt, this, _2 ));
- mCtrlSculptTexture->setDropCallback( boost::bind(&LLPanelObject::onDropSculpt, this, _2 ));
- // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode
- mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
- // Allow any texture to be used during non-immediate mode.
- mCtrlSculptTexture->setNonImmediateFilterPermMask(PERM_NONE);
- LLAggregatePermissions texture_perms;
- if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms))
- {
- BOOL can_copy =
- texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY ||
- texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL;
- BOOL can_transfer =
- texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY ||
- texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL;
- mCtrlSculptTexture->setCanApplyImmediately(can_copy && can_transfer);
- }
- else
- {
- mCtrlSculptTexture->setCanApplyImmediately(FALSE);
- }
- }
-
- mLabelSculptType = getChild<LLTextBox>("label sculpt type");
- mCtrlSculptType = getChild<LLComboBox>("sculpt type control");
- childSetCommitCallback("sculpt type control", onCommitSculptType, this);
- mCtrlSculptMirror = getChild<LLCheckBoxCtrl>("sculpt mirror control");
- childSetCommitCallback("sculpt mirror control", onCommitSculptType, this);
- mCtrlSculptInvert = getChild<LLCheckBoxCtrl>("sculpt invert control");
- childSetCommitCallback("sculpt invert control", onCommitSculptType, this);
-
- // Start with everyone disabled
- clearCtrls();
-
- return TRUE;
-}
-
-LLPanelObject::LLPanelObject()
-: LLPanel(),
- mIsPhysical(FALSE),
- mIsTemporary(FALSE),
- mIsPhantom(FALSE),
- mCastShadows(TRUE),
- mSelectedType(MI_BOX),
- mSculptTextureRevert(LLUUID::null),
- mSculptTypeRevert(0)
-{
-}
-
-
-LLPanelObject::~LLPanelObject()
-{
- // Children all cleaned up by default view destructor.
-}
-
-void LLPanelObject::getState( )
-{
- LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
- LLViewerObject* root_objectp = objectp;
- if(!objectp)
- {
- objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
- // *FIX: shouldn't we just keep the child?
- if (objectp)
- {
- LLViewerObject* parentp = objectp->getRootEdit();
-
- if (parentp)
- {
- root_objectp = parentp;
- }
- else
- {
- root_objectp = objectp;
- }
- }
- }
-
- LLVOVolume *volobjp = NULL;
- if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
- {
- volobjp = (LLVOVolume *)objectp;
- }
-
- if( !objectp )
- {
- //forfeit focus
- if (gFocusMgr.childHasKeyboardFocus(this))
- {
- gFocusMgr.setKeyboardFocus(NULL);
- }
-
- // Disable all text input fields
- clearCtrls();
- return;
- }
-
- // can move or rotate only linked group with move permissions, or sub-object with move and modify perms
- BOOL enable_move = objectp->permMove() && !objectp->isAttachment() && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts"));
- BOOL enable_scale = objectp->permMove() && objectp->permModify();
- BOOL enable_rotate = objectp->permMove() && ( (objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts"));
-
- S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
- BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ))
- && (selected_count == 1);
-
- if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 1)
- {
- enable_move = FALSE;
- enable_scale = FALSE;
- enable_rotate = FALSE;
- }
-
- LLVector3 vec;
- if (enable_move)
- {
- vec = objectp->getPositionEdit();
- mCtrlPosX->set( vec.mV[VX] );
- mCtrlPosY->set( vec.mV[VY] );
- mCtrlPosZ->set( vec.mV[VZ] );
- }
- else
- {
- mCtrlPosX->clear();
- mCtrlPosY->clear();
- mCtrlPosZ->clear();
- }
-
-
- mLabelPosition->setEnabled( enable_move );
- mCtrlPosX->setEnabled(enable_move);
- mCtrlPosY->setEnabled(enable_move);
- mCtrlPosZ->setEnabled(enable_move);
-
- if (enable_scale)
- {
- vec = objectp->getScale();
- mCtrlScaleX->set( vec.mV[VX] );
- mCtrlScaleY->set( vec.mV[VY] );
- mCtrlScaleZ->set( vec.mV[VZ] );
- }
- else
- {
- mCtrlScaleX->clear();
- mCtrlScaleY->clear();
- mCtrlScaleZ->clear();
- }
-
- mLabelSize->setEnabled( enable_scale );
- mCtrlScaleX->setEnabled( enable_scale );
- mCtrlScaleY->setEnabled( enable_scale );
- mCtrlScaleZ->setEnabled( enable_scale );
-
- LLQuaternion object_rot = objectp->getRotationEdit();
- object_rot.getEulerAngles(&(mCurEulerDegrees.mV[VX]), &(mCurEulerDegrees.mV[VY]), &(mCurEulerDegrees.mV[VZ]));
- mCurEulerDegrees *= RAD_TO_DEG;
- mCurEulerDegrees.mV[VX] = fmod(llround(mCurEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
- mCurEulerDegrees.mV[VY] = fmod(llround(mCurEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
- mCurEulerDegrees.mV[VZ] = fmod(llround(mCurEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
-
- if (enable_rotate)
- {
- mCtrlRotX->set( mCurEulerDegrees.mV[VX] );
- mCtrlRotY->set( mCurEulerDegrees.mV[VY] );
- mCtrlRotZ->set( mCurEulerDegrees.mV[VZ] );
- }
- else
- {
- mCtrlRotX->clear();
- mCtrlRotY->clear();
- mCtrlRotZ->clear();
- }
-
- mLabelRotation->setEnabled( enable_rotate );
- mCtrlRotX->setEnabled( enable_rotate );
- mCtrlRotY->setEnabled( enable_rotate );
- mCtrlRotZ->setEnabled( enable_rotate );
-
- BOOL owners_identical;
- LLUUID owner_id;
- std::string owner_name;
- owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
-
- // BUG? Check for all objects being editable?
- S32 roots_selected = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount();
- BOOL editable = root_objectp->permModify();
-
- // Select Single Message
- getChildView("select_single")->setVisible( FALSE);
- getChildView("edit_object")->setVisible( FALSE);
- if (!editable || single_volume || selected_count <= 1)
- {
- getChildView("edit_object")->setVisible( TRUE);
- getChildView("edit_object")->setEnabled(TRUE);
- }
- else
- {
- getChildView("select_single")->setVisible( TRUE);
- getChildView("select_single")->setEnabled(TRUE);
- }
- // Lock checkbox - only modifiable if you own the object.
- BOOL self_owned = (gAgent.getID() == owner_id);
- mCheckLock->setEnabled( roots_selected > 0 && self_owned );
-
- // More lock and debit checkbox - get the values
- BOOL valid;
- U32 owner_mask_on;
- U32 owner_mask_off;
- valid = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER, &owner_mask_on, &owner_mask_off);
-
- if(valid)
- {
- if(owner_mask_on & PERM_MOVE)
- {
- // owner can move, so not locked
- mCheckLock->set(FALSE);
- mCheckLock->setTentative(FALSE);
- }
- else if(owner_mask_off & PERM_MOVE)
- {
- // owner can't move, so locked
- mCheckLock->set(TRUE);
- mCheckLock->setTentative(FALSE);
- }
- else
- {
- // some locked, some not locked
- mCheckLock->set(FALSE);
- mCheckLock->setTentative(TRUE);
- }
- }
-
- BOOL is_flexible = volobjp && volobjp->isFlexible();
-
- // Physics checkbox
- mIsPhysical = root_objectp->usePhysics();
- mCheckPhysics->set( mIsPhysical );
- mCheckPhysics->setEnabled( roots_selected>0
- && (editable || gAgent.isGodlike())
- && !is_flexible);
-
- mIsTemporary = root_objectp->flagTemporaryOnRez();
- mCheckTemporary->set( mIsTemporary );
- mCheckTemporary->setEnabled( roots_selected>0 && editable );
-
- mIsPhantom = root_objectp->flagPhantom();
- mCheckPhantom->set( mIsPhantom );
- mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible );
-
-
-#if 0 // 1.9.2
- mCastShadows = root_objectp->flagCastShadows();
- mCheckCastShadows->set( mCastShadows );
- mCheckCastShadows->setEnabled( roots_selected==1 && editable );
-#endif
-
- //----------------------------------------------------------------------------
-
- S32 selected_item = MI_BOX;
- S32 selected_hole = MI_HOLE_SAME;
- BOOL enabled = FALSE;
- BOOL hole_enabled = FALSE;
- F32 scale_x=1.f, scale_y=1.f;
- BOOL isMesh = FALSE;
-
- if( !objectp || !objectp->getVolume() || !editable || !single_volume)
- {
- // Clear out all geometry fields.
- mComboBaseType->clear();
- mSpinHollow->clear();
- mSpinCutBegin->clear();
- mSpinCutEnd->clear();
- mCtrlPathBegin->clear();
- mCtrlPathEnd->clear();
- mSpinScaleX->clear();
- mSpinScaleY->clear();
- mSpinTwist->clear();
- mSpinTwistBegin->clear();
- mComboHoleType->clear();
- mSpinShearX->clear();
- mSpinShearY->clear();
- mSpinTaperX->clear();
- mSpinTaperY->clear();
- mSpinRadiusOffset->clear();
- mSpinRevolutions->clear();
- mSpinSkew->clear();
-
- mSelectedType = MI_NONE;
- }
- else
- {
- // Only allowed to change these parameters for objects
- // that you have permissions on AND are not attachments.
- enabled = root_objectp->permModify();
-
- // Volume type
- const LLVolumeParams &volume_params = objectp->getVolume()->getParams();
- U8 path = volume_params.getPathParams().getCurveType();
- U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
- U8 profile = profile_and_hole & LL_PCODE_PROFILE_MASK;
- U8 hole = profile_and_hole & LL_PCODE_HOLE_MASK;
-
- // Scale goes first so we can differentiate between a sphere and a torus,
- // which have the same profile and path types.
-
- // Scale
- scale_x = volume_params.getRatioX();
- scale_y = volume_params.getRatioY();
-
- BOOL linear_path = (path == LL_PCODE_PATH_LINE) || (path == LL_PCODE_PATH_FLEXIBLE);
- if ( linear_path && profile == LL_PCODE_PROFILE_CIRCLE )
- {
- selected_item = MI_CYLINDER;
- }
- else if ( linear_path && profile == LL_PCODE_PROFILE_SQUARE )
- {
- selected_item = MI_BOX;
- }
- else if ( linear_path && profile == LL_PCODE_PROFILE_ISOTRI )
- {
- selected_item = MI_PRISM;
- }
- else if ( linear_path && profile == LL_PCODE_PROFILE_EQUALTRI )
- {
- selected_item = MI_PRISM;
- }
- else if ( linear_path && profile == LL_PCODE_PROFILE_RIGHTTRI )
- {
- selected_item = MI_PRISM;
- }
- else if (path == LL_PCODE_PATH_FLEXIBLE) // shouldn't happen
- {
- selected_item = MI_CYLINDER; // reasonable default
- }
- else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y > 0.75f)
- {
- selected_item = MI_SPHERE;
- }
- else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y <= 0.75f)
- {
- selected_item = MI_TORUS;
- }
- else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE_HALF)
- {
- selected_item = MI_SPHERE;
- }
- else if ( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_CIRCLE )
- {
- // Spirals aren't supported. Make it into a sphere. JC
- selected_item = MI_SPHERE;
- }
- else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_EQUALTRI )
- {
- selected_item = MI_RING;
- }
- else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_SQUARE && scale_y <= 0.75f)
- {
- selected_item = MI_TUBE;
- }
- else
- {
- llinfos << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << llendl;
- selected_item = MI_BOX;
- }
-
-
- if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
- {
- selected_item = MI_SCULPT;
- //LLFirstUse::useSculptedPrim();
- }
-
-
- mComboBaseType ->setCurrentByIndex( selected_item );
- mSelectedType = selected_item;
-
- // Grab S path
- F32 begin_s = volume_params.getBeginS();
- F32 end_s = volume_params.getEndS();
-
- // Compute cut and advanced cut from S and T
- F32 begin_t = volume_params.getBeginT();
- F32 end_t = volume_params.getEndT();
-
- // Hollowness
- F32 hollow = volume_params.getHollow();
- mSpinHollow->set( 100.f * hollow );
-
- // All hollow objects allow a shape to be selected.
- if (hollow > 0.f)
- {
- switch (hole)
- {
- case LL_PCODE_HOLE_CIRCLE:
- selected_hole = MI_HOLE_CIRCLE;
- break;
- case LL_PCODE_HOLE_SQUARE:
- selected_hole = MI_HOLE_SQUARE;
- break;
- case LL_PCODE_HOLE_TRIANGLE:
- selected_hole = MI_HOLE_TRIANGLE;
- break;
- case LL_PCODE_HOLE_SAME:
- default:
- selected_hole = MI_HOLE_SAME;
- break;
- }
- mComboHoleType->setCurrentByIndex( selected_hole );
- hole_enabled = enabled;
- }
- else
- {
- mComboHoleType->setCurrentByIndex( MI_HOLE_SAME );
- hole_enabled = FALSE;
- }
-
- // Cut interpretation varies based on base object type
- F32 cut_begin, cut_end, adv_cut_begin, adv_cut_end;
-
- if ( selected_item == MI_SPHERE || selected_item == MI_TORUS ||
- selected_item == MI_TUBE || selected_item == MI_RING )
- {
- cut_begin = begin_t;
- cut_end = end_t;
- adv_cut_begin = begin_s;
- adv_cut_end = end_s;
- }
- else
- {
- cut_begin = begin_s;
- cut_end = end_s;
- adv_cut_begin = begin_t;
- adv_cut_end = end_t;
- }
-
- mSpinCutBegin ->set( cut_begin );
- mSpinCutEnd ->set( cut_end );
- mCtrlPathBegin ->set( adv_cut_begin );
- mCtrlPathEnd ->set( adv_cut_end );
-
- // Twist
- F32 twist = volume_params.getTwist();
- F32 twist_begin = volume_params.getTwistBegin();
- // Check the path type for conversion.
- if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE)
- {
- twist *= OBJECT_TWIST_LINEAR_MAX;
- twist_begin *= OBJECT_TWIST_LINEAR_MAX;
- }
- else
- {
- twist *= OBJECT_TWIST_MAX;
- twist_begin *= OBJECT_TWIST_MAX;
- }
-
- mSpinTwist ->set( twist );
- mSpinTwistBegin ->set( twist_begin );
-
- // Shear
- F32 shear_x = volume_params.getShearX();
- F32 shear_y = volume_params.getShearY();
- mSpinShearX->set( shear_x );
- mSpinShearY->set( shear_y );
-
- // Taper
- F32 taper_x = volume_params.getTaperX();
- F32 taper_y = volume_params.getTaperY();
- mSpinTaperX->set( taper_x );
- mSpinTaperY->set( taper_y );
-
- // Radius offset.
- F32 radius_offset = volume_params.getRadiusOffset();
- // Limit radius offset, based on taper and hole size y.
- F32 radius_mag = fabs(radius_offset);
- F32 hole_y_mag = fabs(scale_y);
- F32 taper_y_mag = fabs(taper_y);
- // Check to see if the taper effects us.
- if ( (radius_offset > 0.f && taper_y < 0.f) ||
- (radius_offset < 0.f && taper_y > 0.f) )
- {
- // The taper does not help increase the radius offset range.
- taper_y_mag = 0.f;
- }
- F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
- // Enforce the maximum magnitude.
- if (radius_mag > max_radius_mag)
- {
- // Check radius offset sign.
- if (radius_offset < 0.f)
- {
- radius_offset = -max_radius_mag;
- }
- else
- {
- radius_offset = max_radius_mag;
- }
- }
- mSpinRadiusOffset->set( radius_offset);
-
- // Revolutions
- F32 revolutions = volume_params.getRevolutions();
- mSpinRevolutions->set( revolutions );
-
- // Skew
- F32 skew = volume_params.getSkew();
- // Limit skew, based on revolutions hole size x.
- F32 skew_mag= fabs(skew);
- F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
- // Discontinuity; A revolution of 1 allows skews below 0.5.
- if ( fabs(revolutions - 1.0f) < 0.001)
- min_skew_mag = 0.0f;
-
- // Clip skew.
- if (skew_mag < min_skew_mag)
- {
- // Check skew sign.
- if (skew < 0.0f)
- {
- skew = -min_skew_mag;
- }
- else
- {
- skew = min_skew_mag;
- }
- }
- mSpinSkew->set( skew );
- }
-
- // Compute control visibility, label names, and twist range.
- // Start with defaults.
- BOOL cut_visible = TRUE;
- BOOL hollow_visible = TRUE;
- BOOL top_size_x_visible = TRUE;
- BOOL top_size_y_visible = TRUE;
- BOOL top_shear_x_visible = TRUE;
- BOOL top_shear_y_visible = TRUE;
- BOOL twist_visible = TRUE;
- BOOL advanced_cut_visible = FALSE;
- BOOL taper_visible = FALSE;
- BOOL skew_visible = FALSE;
- BOOL radius_offset_visible = FALSE;
- BOOL revolutions_visible = FALSE;
- BOOL sculpt_texture_visible = FALSE;
- F32 twist_min = OBJECT_TWIST_LINEAR_MIN;
- F32 twist_max = OBJECT_TWIST_LINEAR_MAX;
- F32 twist_inc = OBJECT_TWIST_LINEAR_INC;
-
- BOOL advanced_is_dimple = FALSE;
- BOOL advanced_is_slice = FALSE;
- BOOL size_is_hole = FALSE;
-
- // Tune based on overall volume type
- switch (selected_item)
- {
- case MI_SPHERE:
- top_size_x_visible = FALSE;
- top_size_y_visible = FALSE;
- top_shear_x_visible = FALSE;
- top_shear_y_visible = FALSE;
- //twist_visible = FALSE;
- advanced_cut_visible = TRUE;
- advanced_is_dimple = TRUE;
- twist_min = OBJECT_TWIST_MIN;
- twist_max = OBJECT_TWIST_MAX;
- twist_inc = OBJECT_TWIST_INC;
- break;
-
- case MI_TORUS:
- case MI_TUBE:
- case MI_RING:
- //top_size_x_visible = FALSE;
- //top_size_y_visible = FALSE;
- size_is_hole = TRUE;
- skew_visible = TRUE;
- advanced_cut_visible = TRUE;
- taper_visible = TRUE;
- radius_offset_visible = TRUE;
- revolutions_visible = TRUE;
- twist_min = OBJECT_TWIST_MIN;
- twist_max = OBJECT_TWIST_MAX;
- twist_inc = OBJECT_TWIST_INC;
-
- break;
-
- case MI_SCULPT:
- cut_visible = FALSE;
- hollow_visible = FALSE;
- twist_visible = FALSE;
- top_size_x_visible = FALSE;
- top_size_y_visible = FALSE;
- top_shear_x_visible = FALSE;
- top_shear_y_visible = FALSE;
- skew_visible = FALSE;
- advanced_cut_visible = FALSE;
- taper_visible = FALSE;
- radius_offset_visible = FALSE;
- revolutions_visible = FALSE;
- sculpt_texture_visible = TRUE;
-
- break;
-
- case MI_BOX:
- advanced_cut_visible = TRUE;
- advanced_is_slice = TRUE;
- break;
-
- case MI_CYLINDER:
- advanced_cut_visible = TRUE;
- advanced_is_slice = TRUE;
- break;
-
- case MI_PRISM:
- advanced_cut_visible = TRUE;
- advanced_is_slice = TRUE;
- break;
-
- default:
- break;
- }
-
- // Check if we need to change top size/hole size params.
- switch (selected_item)
- {
- case MI_SPHERE:
- case MI_TORUS:
- case MI_TUBE:
- case MI_RING:
- mSpinScaleX->set( scale_x );
- mSpinScaleY->set( scale_y );
- mSpinScaleX->setMinValue(OBJECT_MIN_HOLE_SIZE);
- mSpinScaleX->setMaxValue(OBJECT_MAX_HOLE_SIZE_X);
- mSpinScaleY->setMinValue(OBJECT_MIN_HOLE_SIZE);
- mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y);
- break;
- default:
- if (editable)
- {
- mSpinScaleX->set( 1.f - scale_x );
- mSpinScaleY->set( 1.f - scale_y );
- mSpinScaleX->setMinValue(-1.f);
- mSpinScaleX->setMaxValue(1.f);
- mSpinScaleY->setMinValue(-1.f);
- mSpinScaleY->setMaxValue(1.f);
- }
- break;
- }
-
- // Check if we need to limit the hollow based on the hole type.
- if ( selected_hole == MI_HOLE_SQUARE &&
- ( selected_item == MI_CYLINDER || selected_item == MI_TORUS ||
- selected_item == MI_PRISM || selected_item == MI_RING ||
- selected_item == MI_SPHERE ) )
- {
- mSpinHollow->setMinValue(0.f);
- mSpinHollow->setMaxValue(70.f);
- }
- else
- {
- mSpinHollow->setMinValue(0.f);
- mSpinHollow->setMaxValue(95.f);
- }
-
- // Update field enablement
- mComboBaseType ->setEnabled( enabled );
-
- mLabelCut ->setEnabled( enabled );
- mSpinCutBegin ->setEnabled( enabled );
- mSpinCutEnd ->setEnabled( enabled );
-
- mLabelHollow ->setEnabled( enabled );
- mSpinHollow ->setEnabled( enabled );
- mLabelHoleType ->setEnabled( hole_enabled );
- mComboHoleType ->setEnabled( hole_enabled );
-
- mLabelTwist ->setEnabled( enabled );
- mSpinTwist ->setEnabled( enabled );
- mSpinTwistBegin ->setEnabled( enabled );
-
- mLabelSkew ->setEnabled( enabled );
- mSpinSkew ->setEnabled( enabled );
-
- getChildView("scale_hole")->setVisible( FALSE);
- getChildView("scale_taper")->setVisible( FALSE);
- if (top_size_x_visible || top_size_y_visible)
- {
- if (size_is_hole)
- {
- getChildView("scale_hole")->setVisible( TRUE);
- getChildView("scale_hole")->setEnabled(enabled);
- }
- else
- {
- getChildView("scale_taper")->setVisible( TRUE);
- getChildView("scale_taper")->setEnabled(enabled);
- }
- }
-
- mSpinScaleX ->setEnabled( enabled );
- mSpinScaleY ->setEnabled( enabled );
-
- mLabelShear ->setEnabled( enabled );
- mSpinShearX ->setEnabled( enabled );
- mSpinShearY ->setEnabled( enabled );
-
- getChildView("advanced_cut")->setVisible( FALSE);
- getChildView("advanced_dimple")->setVisible( FALSE);
- getChildView("advanced_slice")->setVisible( FALSE);
-
- if (advanced_cut_visible)
- {
- if (advanced_is_dimple)
- {
- getChildView("advanced_dimple")->setVisible( TRUE);
- getChildView("advanced_dimple")->setEnabled(enabled);
- }
-
- else if (advanced_is_slice)
- {
- getChildView("advanced_slice")->setVisible( TRUE);
- getChildView("advanced_slice")->setEnabled(enabled);
- }
- else
- {
- getChildView("advanced_cut")->setVisible( TRUE);
- getChildView("advanced_cut")->setEnabled(enabled);
- }
- }
-
- mCtrlPathBegin ->setEnabled( enabled );
- mCtrlPathEnd ->setEnabled( enabled );
-
- mLabelTaper ->setEnabled( enabled );
- mSpinTaperX ->setEnabled( enabled );
- mSpinTaperY ->setEnabled( enabled );
-
- mLabelRadiusOffset->setEnabled( enabled );
- mSpinRadiusOffset ->setEnabled( enabled );
-
- mLabelRevolutions->setEnabled( enabled );
- mSpinRevolutions ->setEnabled( enabled );
-
- // Update field visibility
- mLabelCut ->setVisible( cut_visible );
- mSpinCutBegin ->setVisible( cut_visible );
- mSpinCutEnd ->setVisible( cut_visible );
-
- mLabelHollow ->setVisible( hollow_visible );
- mSpinHollow ->setVisible( hollow_visible );
- mLabelHoleType ->setVisible( hollow_visible );
- mComboHoleType ->setVisible( hollow_visible );
-
- mLabelTwist ->setVisible( twist_visible );
- mSpinTwist ->setVisible( twist_visible );
- mSpinTwistBegin ->setVisible( twist_visible );
- mSpinTwist ->setMinValue( twist_min );
- mSpinTwist ->setMaxValue( twist_max );
- mSpinTwist ->setIncrement( twist_inc );
- mSpinTwistBegin ->setMinValue( twist_min );
- mSpinTwistBegin ->setMaxValue( twist_max );
- mSpinTwistBegin ->setIncrement( twist_inc );
-
- mSpinScaleX ->setVisible( top_size_x_visible );
- mSpinScaleY ->setVisible( top_size_y_visible );
-
- mLabelSkew ->setVisible( skew_visible );
- mSpinSkew ->setVisible( skew_visible );
-
- mLabelShear ->setVisible( top_shear_x_visible || top_shear_y_visible );
- mSpinShearX ->setVisible( top_shear_x_visible );
- mSpinShearY ->setVisible( top_shear_y_visible );
-
- mCtrlPathBegin ->setVisible( advanced_cut_visible );
- mCtrlPathEnd ->setVisible( advanced_cut_visible );
-
- mLabelTaper ->setVisible( taper_visible );
- mSpinTaperX ->setVisible( taper_visible );
- mSpinTaperY ->setVisible( taper_visible );
-
- mLabelRadiusOffset->setVisible( radius_offset_visible );
- mSpinRadiusOffset ->setVisible( radius_offset_visible );
-
- mLabelRevolutions->setVisible( revolutions_visible );
- mSpinRevolutions ->setVisible( revolutions_visible );
-
- mCtrlSculptTexture->setVisible(sculpt_texture_visible);
- mLabelSculptType->setVisible(sculpt_texture_visible);
- mCtrlSculptType->setVisible(sculpt_texture_visible);
-
-
- // sculpt texture
- if (selected_item == MI_SCULPT)
- {
-
-
- LLUUID id;
- LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
-
-
- if (sculpt_params) // if we have a legal sculpt param block for this object:
- {
- if (mObject != objectp) // we've just selected a new object, so save for undo
- {
- mSculptTextureRevert = sculpt_params->getSculptTexture();
- mSculptTypeRevert = sculpt_params->getSculptType();
- }
-
- U8 sculpt_type = sculpt_params->getSculptType();
- U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
- BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
- BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
- isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH);
-
- LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
- if(mTextureCtrl)
- {
- mTextureCtrl->setTentative(FALSE);
- mTextureCtrl->setEnabled(editable && !isMesh);
- if (editable)
- mTextureCtrl->setImageAssetID(sculpt_params->getSculptTexture());
- else
- mTextureCtrl->setImageAssetID(LLUUID::null);
- }
-
- mComboBaseType->setEnabled(!isMesh);
-
- if (mCtrlSculptType)
- {
- mCtrlSculptType->setCurrentByIndex(sculpt_stitching);
- mCtrlSculptType->setEnabled(editable && !isMesh);
- }
-
- if (mCtrlSculptMirror)
- {
- mCtrlSculptMirror->set(sculpt_mirror);
- mCtrlSculptMirror->setEnabled(editable && !isMesh);
- }
-
- if (mCtrlSculptInvert)
- {
- mCtrlSculptInvert->set(sculpt_invert);
- mCtrlSculptInvert->setEnabled(editable);
- }
-
- if (mLabelSculptType)
- {
- mLabelSculptType->setEnabled(TRUE);
- }
-
- }
- }
- else
- {
- mSculptTextureRevert = LLUUID::null;
- }
-
- mCtrlSculptMirror->setVisible(sculpt_texture_visible && !isMesh);
- mCtrlSculptInvert->setVisible(sculpt_texture_visible && !isMesh);
-
- //----------------------------------------------------------------------------
-
- mObject = objectp;
- mRootObject = root_objectp;
-}
-
-// static
-bool LLPanelObject::precommitValidate( const LLSD& data )
-{
- // TODO: Richard will fill this in later.
- return TRUE; // FALSE means that validation failed and new value should not be commited.
-}
-
-void LLPanelObject::sendIsPhysical()
-{
- BOOL value = mCheckPhysics->get();
- if( mIsPhysical != value )
- {
- LLSelectMgr::getInstance()->selectionUpdatePhysics(value);
- mIsPhysical = value;
-
- llinfos << "update physics sent" << llendl;
- }
- else
- {
- llinfos << "update physics not changed" << llendl;
- }
-}
-
-void LLPanelObject::sendIsTemporary()
-{
- BOOL value = mCheckTemporary->get();
- if( mIsTemporary != value )
- {
- LLSelectMgr::getInstance()->selectionUpdateTemporary(value);
- mIsTemporary = value;
-
- llinfos << "update temporary sent" << llendl;
- }
- else
- {
- llinfos << "update temporary not changed" << llendl;
- }
-}
-
-
-void LLPanelObject::sendIsPhantom()
-{
- BOOL value = mCheckPhantom->get();
- if( mIsPhantom != value )
- {
- LLSelectMgr::getInstance()->selectionUpdatePhantom(value);
- mIsPhantom = value;
-
- llinfos << "update phantom sent" << llendl;
- }
- else
- {
- llinfos << "update phantom not changed" << llendl;
- }
-}
-
-void LLPanelObject::sendCastShadows()
-{
- BOOL value = mCheckCastShadows->get();
- if( mCastShadows != value )
- {
- LLSelectMgr::getInstance()->selectionUpdateCastShadows(value);
- mCastShadows = value;
-
- llinfos << "update cast shadows sent" << llendl;
- }
- else
- {
- llinfos << "update cast shadows not changed" << llendl;
- }
-}
-
-// static
-void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata )
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
-
- if (self->mObject.isNull())
- {
- return;
- }
-
- if (self->mObject->getPCode() != LL_PCODE_VOLUME)
- {
- // Don't allow modification of non-volume objects.
- return;
- }
-
- LLVolume *volume = self->mObject->getVolume();
- if (!volume)
- {
- return;
- }
-
- LLVolumeParams volume_params;
- self->getVolumeParams(volume_params);
-
-
-
- // set sculpting
- S32 selected_type = self->mComboBaseType->getCurrentIndex();
-
- if (selected_type == MI_SCULPT)
- {
- self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, TRUE, TRUE);
- LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
- if (sculpt_params)
- volume_params.setSculptID(sculpt_params->getSculptTexture(), sculpt_params->getSculptType());
- }
- else
- {
- LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
- if (sculpt_params)
- self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE);
- }
-
- // Update the volume, if necessary.
- self->mObject->updateVolume(volume_params);
-
-
- // This was added to make sure thate when changes are made, the UI
- // adjusts to present valid options.
- // *FIX: only some changes, ie, hollow or primitive type changes,
- // require a refresh.
- self->refresh();
-
-}
-
-void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
-{
- // Figure out what type of volume to make
- S32 was_selected_type = mSelectedType;
- S32 selected_type = mComboBaseType->getCurrentIndex();
- U8 profile;
- U8 path;
- switch ( selected_type )
- {
- case MI_CYLINDER:
- profile = LL_PCODE_PROFILE_CIRCLE;
- path = LL_PCODE_PATH_LINE;
- break;
-
- case MI_BOX:
- profile = LL_PCODE_PROFILE_SQUARE;
- path = LL_PCODE_PATH_LINE;
- break;
-
- case MI_PRISM:
- profile = LL_PCODE_PROFILE_EQUALTRI;
- path = LL_PCODE_PATH_LINE;
- break;
-
- case MI_SPHERE:
- profile = LL_PCODE_PROFILE_CIRCLE_HALF;
- path = LL_PCODE_PATH_CIRCLE;
- break;
-
- case MI_TORUS:
- profile = LL_PCODE_PROFILE_CIRCLE;
- path = LL_PCODE_PATH_CIRCLE;
- break;
-
- case MI_TUBE:
- profile = LL_PCODE_PROFILE_SQUARE;
- path = LL_PCODE_PATH_CIRCLE;
- break;
-
- case MI_RING:
- profile = LL_PCODE_PROFILE_EQUALTRI;
- path = LL_PCODE_PATH_CIRCLE;
- break;
-
- case MI_SCULPT:
- profile = LL_PCODE_PROFILE_CIRCLE;
- path = LL_PCODE_PATH_CIRCLE;
- break;
-
- default:
- llwarns << "Unknown base type " << selected_type
- << " in getVolumeParams()" << llendl;
- // assume a box
- selected_type = MI_BOX;
- profile = LL_PCODE_PROFILE_SQUARE;
- path = LL_PCODE_PATH_LINE;
- break;
- }
-
-
- if (path == LL_PCODE_PATH_LINE)
- {
- LLVOVolume *volobjp = (LLVOVolume *)(LLViewerObject*)(mObject);
- if (volobjp->isFlexible())
- {
- path = LL_PCODE_PATH_FLEXIBLE;
- }
- }
-
- S32 selected_hole = mComboHoleType->getCurrentIndex();
- U8 hole;
- switch (selected_hole)
- {
- case MI_HOLE_CIRCLE:
- hole = LL_PCODE_HOLE_CIRCLE;
- break;
- case MI_HOLE_SQUARE:
- hole = LL_PCODE_HOLE_SQUARE;
- break;
- case MI_HOLE_TRIANGLE:
- hole = LL_PCODE_HOLE_TRIANGLE;
- break;
- case MI_HOLE_SAME:
- default:
- hole = LL_PCODE_HOLE_SAME;
- break;
- }
-
- volume_params.setType(profile | hole, path);
- mSelectedType = selected_type;
-
- // Compute cut start/end
- F32 cut_begin = mSpinCutBegin->get();
- F32 cut_end = mSpinCutEnd->get();
-
- // Make sure at least OBJECT_CUT_INC of the object survives
- if (cut_begin > cut_end - OBJECT_MIN_CUT_INC)
- {
- cut_begin = cut_end - OBJECT_MIN_CUT_INC;
- mSpinCutBegin->set(cut_begin);
- }
-
- F32 adv_cut_begin = mCtrlPathBegin->get();
- F32 adv_cut_end = mCtrlPathEnd->get();
-
- // Make sure at least OBJECT_CUT_INC of the object survives
- if (adv_cut_begin > adv_cut_end - OBJECT_MIN_CUT_INC)
- {
- adv_cut_begin = adv_cut_end - OBJECT_MIN_CUT_INC;
- mCtrlPathBegin->set(adv_cut_begin);
- }
-
- F32 begin_s, end_s;
- F32 begin_t, end_t;
-
- if (selected_type == MI_SPHERE || selected_type == MI_TORUS ||
- selected_type == MI_TUBE || selected_type == MI_RING)
- {
- begin_s = adv_cut_begin;
- end_s = adv_cut_end;
-
- begin_t = cut_begin;
- end_t = cut_end;
- }
- else
- {
- begin_s = cut_begin;
- end_s = cut_end;
-
- begin_t = adv_cut_begin;
- end_t = adv_cut_end;
- }
-
- volume_params.setBeginAndEndS(begin_s, end_s);
- volume_params.setBeginAndEndT(begin_t, end_t);
-
- // Hollowness
- F32 hollow = mSpinHollow->get() / 100.f;
-
- if ( selected_hole == MI_HOLE_SQUARE &&
- ( selected_type == MI_CYLINDER || selected_type == MI_TORUS ||
- selected_type == MI_PRISM || selected_type == MI_RING ||
- selected_type == MI_SPHERE ) )
- {
- if (hollow > 0.7f) hollow = 0.7f;
- }
-
- volume_params.setHollow( hollow );
-
- // Twist Begin,End
- F32 twist_begin = mSpinTwistBegin->get();
- F32 twist = mSpinTwist->get();
- // Check the path type for twist conversion.
- if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE)
- {
- twist_begin /= OBJECT_TWIST_LINEAR_MAX;
- twist /= OBJECT_TWIST_LINEAR_MAX;
- }
- else
- {
- twist_begin /= OBJECT_TWIST_MAX;
- twist /= OBJECT_TWIST_MAX;
- }
-
- volume_params.setTwistBegin(twist_begin);
- volume_params.setTwist(twist);
-
- // Scale X,Y
- F32 scale_x = mSpinScaleX->get();
- F32 scale_y = mSpinScaleY->get();
- if ( was_selected_type == MI_BOX || was_selected_type == MI_CYLINDER || was_selected_type == MI_PRISM)
- {
- scale_x = 1.f - scale_x;
- scale_y = 1.f - scale_y;
- }
-
- // Skew
- F32 skew = mSpinSkew->get();
-
- // Taper X,Y
- F32 taper_x = mSpinTaperX->get();
- F32 taper_y = mSpinTaperY->get();
-
- // Radius offset
- F32 radius_offset = mSpinRadiusOffset->get();
-
- // Revolutions
- F32 revolutions = mSpinRevolutions->get();
-
- if ( selected_type == MI_SPHERE )
- {
- // Snap values to valid sphere parameters.
- scale_x = 1.0f;
- scale_y = 1.0f;
- skew = 0.0f;
- taper_x = 0.0f;
- taper_y = 0.0f;
- radius_offset = 0.0f;
- revolutions = 1.0f;
- }
- else if ( selected_type == MI_TORUS || selected_type == MI_TUBE ||
- selected_type == MI_RING )
- {
- scale_x = llclamp(
- scale_x,
- OBJECT_MIN_HOLE_SIZE,
- OBJECT_MAX_HOLE_SIZE_X);
- scale_y = llclamp(
- scale_y,
- OBJECT_MIN_HOLE_SIZE,
- OBJECT_MAX_HOLE_SIZE_Y);
-
- // Limit radius offset, based on taper and hole size y.
- F32 radius_mag = fabs(radius_offset);
- F32 hole_y_mag = fabs(scale_y);
- F32 taper_y_mag = fabs(taper_y);
- // Check to see if the taper effects us.
- if ( (radius_offset > 0.f && taper_y < 0.f) ||
- (radius_offset < 0.f && taper_y > 0.f) )
- {
- // The taper does not help increase the radius offset range.
- taper_y_mag = 0.f;
- }
- F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
- // Enforce the maximum magnitude.
- if (radius_mag > max_radius_mag)
- {
- // Check radius offset sign.
- if (radius_offset < 0.f)
- {
- radius_offset = -max_radius_mag;
- }
- else
- {
- radius_offset = max_radius_mag;
- }
- }
-
- // Check the skew value against the revolutions.
- F32 skew_mag= fabs(skew);
- F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
- // Discontinuity; A revolution of 1 allows skews below 0.5.
- if ( fabs(revolutions - 1.0f) < 0.001)
- min_skew_mag = 0.0f;
-
- // Clip skew.
- if (skew_mag < min_skew_mag)
- {
- // Check skew sign.
- if (skew < 0.0f)
- {
- skew = -min_skew_mag;
- }
- else
- {
- skew = min_skew_mag;
- }
- }
- }
-
- volume_params.setRatio( scale_x, scale_y );
- volume_params.setSkew(skew);
- volume_params.setTaper( taper_x, taper_y );
- volume_params.setRadiusOffset(radius_offset);
- volume_params.setRevolutions(revolutions);
-
- // Shear X,Y
- F32 shear_x = mSpinShearX->get();
- F32 shear_y = mSpinShearY->get();
- volume_params.setShear( shear_x, shear_y );
-
- if (selected_type == MI_SCULPT)
- {
- volume_params.setSculptID(LLUUID::null, 0);
- volume_params.setBeginAndEndT (0, 1);
- volume_params.setBeginAndEndS (0, 1);
- volume_params.setHollow (0);
- volume_params.setTwistBegin (0);
- volume_params.setTwistEnd (0);
- volume_params.setRatio (1, 0.5);
- volume_params.setShear (0, 0);
- volume_params.setTaper (0, 0);
- volume_params.setRevolutions (1);
- volume_params.setRadiusOffset (0);
- volume_params.setSkew (0);
- }
-
-}
-
-// BUG: Make work with multiple objects
-void LLPanelObject::sendRotation(BOOL btn_down)
-{
- if (mObject.isNull()) return;
-
- LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get());
- new_rot.mV[VX] = llround(new_rot.mV[VX], OBJECT_ROTATION_PRECISION);
- new_rot.mV[VY] = llround(new_rot.mV[VY], OBJECT_ROTATION_PRECISION);
- new_rot.mV[VZ] = llround(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION);
-
- // Note: must compare before conversion to radians
- LLVector3 delta = new_rot - mCurEulerDegrees;
-
- if (delta.magVec() >= 0.0005f)
- {
- mCurEulerDegrees = new_rot;
- new_rot *= DEG_TO_RAD;
-
- LLQuaternion rotation;
- rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]);
-
- if (mRootObject != mObject)
- {
- rotation = rotation * ~mRootObject->getRotationRegion();
- }
- std::vector<LLVector3>& child_positions = mObject->mUnselectedChildrenPositions ;
- std::vector<LLQuaternion> child_rotations;
- if (mObject->isRootEdit())
- {
- mObject->saveUnselectedChildrenRotation(child_rotations) ;
- mObject->saveUnselectedChildrenPosition(child_positions) ;
- }
-
- mObject->setRotation(rotation);
- LLManip::rebuild(mObject) ;
-
- // for individually selected roots, we need to counterrotate all the children
- if (mObject->isRootEdit())
- {
- mObject->resetChildrenRotationAndPosition(child_rotations, child_positions) ;
- }
-
- if(!btn_down)
- {
- child_positions.clear() ;
- LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_ROTATION | UPD_POSITION);
- }
- }
-}
-
-
-// BUG: Make work with multiple objects
-void LLPanelObject::sendScale(BOOL btn_down)
-{
- if (mObject.isNull()) return;
-
- LLVector3 newscale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get());
-
- LLVector3 delta = newscale - mObject->getScale();
- if (delta.magVec() >= 0.0005f)
- {
- // scale changed by more than 1/2 millimeter
-
- // check to see if we aren't scaling the textures
- // (in which case the tex coord's need to be recomputed)
- BOOL dont_stretch_textures = !LLManipScale::getStretchTextures();
- if (dont_stretch_textures)
- {
- LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE);
- }
-
- mObject->setScale(newscale, TRUE);
-
- if(!btn_down)
- {
- LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_SCALE | UPD_POSITION);
- }
-
- LLSelectMgr::getInstance()->adjustTexturesByScale(TRUE, !dont_stretch_textures);
-// llinfos << "scale sent" << llendl;
- }
- else
- {
-// llinfos << "scale not changed" << llendl;
- }
-}
-
-
-void LLPanelObject::sendPosition(BOOL btn_down)
-{
- if (mObject.isNull()) return;
-
- LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
- LLViewerRegion* regionp = mObject->getRegion();
-
- // Clamp the Z height
- const F32 height = newpos.mV[VZ];
- const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal());
- const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight();
-
- if (!mObject->isAttachment())
- {
- if ( height < min_height)
- {
- newpos.mV[VZ] = min_height;
- mCtrlPosZ->set( min_height );
- }
- else if ( height > max_height )
- {
- newpos.mV[VZ] = max_height;
- mCtrlPosZ->set( max_height );
- }
-
- // Grass is always drawn on the ground, so clamp its position to the ground
- if (mObject->getPCode() == LL_PCODE_LEGACY_GRASS)
- {
- mCtrlPosZ->set(LLWorld::getInstance()->resolveLandHeightAgent(newpos) + 1.f);
- }
- }
-
- // Make sure new position is in a valid region, so the object
- // won't get dumped by the simulator.
- LLVector3d new_pos_global = regionp->getPosGlobalFromRegion(newpos);
-
- if ( LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global) )
- {
- // send only if the position is changed, that is, the delta vector is not zero
- LLVector3d old_pos_global = mObject->getPositionGlobal();
- LLVector3d delta = new_pos_global - old_pos_global;
- // moved more than 1/2 millimeter
- if (delta.magVec() >= 0.0005f)
- {
- if (mRootObject != mObject)
- {
- newpos = newpos - mRootObject->getPositionRegion();
- newpos = newpos * ~mRootObject->getRotationRegion();
- mObject->setPositionParent(newpos);
- }
- else
- {
- mObject->setPositionEdit(newpos);
- }
-
- LLManip::rebuild(mObject) ;
-
- // for individually selected roots, we need to counter-translate all unselected children
- if (mObject->isRootEdit())
- {
- // only offset by parent's translation
- mObject->resetChildrenPosition(LLVector3(-delta), TRUE) ;
- }
-
- if(!btn_down)
- {
- LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION);
- }
-
- LLSelectMgr::getInstance()->updateSelectionCenter();
- }
- }
- else
- {
- // move failed, so we update the UI with the correct values
- LLVector3 vec = mRootObject->getPositionRegion();
- mCtrlPosX->set(vec.mV[VX]);
- mCtrlPosY->set(vec.mV[VY]);
- mCtrlPosZ->set(vec.mV[VZ]);
- }
-}
-
-void LLPanelObject::sendSculpt()
-{
- if (mObject.isNull())
- return;
-
- LLSculptParams sculpt_params;
-
- if (mCtrlSculptTexture)
- sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID());
-
- U8 sculpt_type = 0;
-
- if (mCtrlSculptType)
- sculpt_type |= mCtrlSculptType->getCurrentIndex();
-
- bool enabled = sculpt_type != LL_SCULPT_TYPE_MESH;
-
- if (mCtrlSculptMirror)
- {
- mCtrlSculptMirror->setEnabled(enabled ? TRUE : FALSE);
- }
- if (mCtrlSculptInvert)
- {
- mCtrlSculptInvert->setEnabled(enabled ? TRUE : FALSE);
- }
-
- if ((mCtrlSculptMirror) && (mCtrlSculptMirror->get()))
- sculpt_type |= LL_SCULPT_FLAG_MIRROR;
-
- if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get()))
- sculpt_type |= LL_SCULPT_FLAG_INVERT;
-
- sculpt_params.setSculptType(sculpt_type);
- mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
-}
-
-void LLPanelObject::refresh()
-{
- getState();
- if (mObject.notNull() && mObject->isDead())
- {
- mObject = NULL;
- }
-
- if (mRootObject.notNull() && mRootObject->isDead())
- {
- mRootObject = NULL;
- }
-
- bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") &&
- gAgent.getRegion() &&
- !gAgent.getRegion()->getCapability("GetMesh").empty();
-
- F32 max_scale = get_default_max_prim_scale(LLPickInfo::isFlora(mObject));
-
- getChild<LLSpinCtrl>("Scale X")->setMaxValue(max_scale);
- getChild<LLSpinCtrl>("Scale Y")->setMaxValue(max_scale);
- getChild<LLSpinCtrl>("Scale Z")->setMaxValue(max_scale);
-
- BOOL found = mCtrlSculptType->itemExists("Mesh");
- if (enable_mesh && !found)
- {
- mCtrlSculptType->add("Mesh");
- }
- else if (!enable_mesh && found)
- {
- mCtrlSculptType->remove("Mesh");
- }
-}
-
-
-void LLPanelObject::draw()
-{
- const LLColor4 white( 1.0f, 1.0f, 1.0f, 1);
- const LLColor4 red( 1.0f, 0.25f, 0.f, 1);
- const LLColor4 green( 0.f, 1.0f, 0.f, 1);
- const LLColor4 blue( 0.f, 0.5f, 1.0f, 1);
-
- // Tune the colors of the labels
- LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
-
- if (tool == LLToolCompTranslate::getInstance())
- {
- mCtrlPosX ->setLabelColor(red);
- mCtrlPosY ->setLabelColor(green);
- mCtrlPosZ ->setLabelColor(blue);
-
- mCtrlScaleX ->setLabelColor(white);
- mCtrlScaleY ->setLabelColor(white);
- mCtrlScaleZ ->setLabelColor(white);
-
- mCtrlRotX ->setLabelColor(white);
- mCtrlRotY ->setLabelColor(white);
- mCtrlRotZ ->setLabelColor(white);
- }
- else if ( tool == LLToolCompScale::getInstance() )
- {
- mCtrlPosX ->setLabelColor(white);
- mCtrlPosY ->setLabelColor(white);
- mCtrlPosZ ->setLabelColor(white);
-
- mCtrlScaleX ->setLabelColor(red);
- mCtrlScaleY ->setLabelColor(green);
- mCtrlScaleZ ->setLabelColor(blue);
-
- mCtrlRotX ->setLabelColor(white);
- mCtrlRotY ->setLabelColor(white);
- mCtrlRotZ ->setLabelColor(white);
- }
- else if ( tool == LLToolCompRotate::getInstance() )
- {
- mCtrlPosX ->setLabelColor(white);
- mCtrlPosY ->setLabelColor(white);
- mCtrlPosZ ->setLabelColor(white);
-
- mCtrlScaleX ->setLabelColor(white);
- mCtrlScaleY ->setLabelColor(white);
- mCtrlScaleZ ->setLabelColor(white);
-
- mCtrlRotX ->setLabelColor(red);
- mCtrlRotY ->setLabelColor(green);
- mCtrlRotZ ->setLabelColor(blue);
- }
- else
- {
- mCtrlPosX ->setLabelColor(white);
- mCtrlPosY ->setLabelColor(white);
- mCtrlPosZ ->setLabelColor(white);
-
- mCtrlScaleX ->setLabelColor(white);
- mCtrlScaleY ->setLabelColor(white);
- mCtrlScaleZ ->setLabelColor(white);
-
- mCtrlRotX ->setLabelColor(white);
- mCtrlRotY ->setLabelColor(white);
- mCtrlRotZ ->setLabelColor(white);
- }
-
- LLPanel::draw();
-}
-
-// virtual
-void LLPanelObject::clearCtrls()
-{
- LLPanel::clearCtrls();
-
- mCheckLock ->set(FALSE);
- mCheckLock ->setEnabled( FALSE );
- mCheckPhysics ->set(FALSE);
- mCheckPhysics ->setEnabled( FALSE );
- mCheckTemporary ->set(FALSE);
- mCheckTemporary ->setEnabled( FALSE );
- mCheckPhantom ->set(FALSE);
- mCheckPhantom ->setEnabled( FALSE );
-
-#if 0 // 1.9.2
- mCheckCastShadows->set(FALSE);
- mCheckCastShadows->setEnabled( FALSE );
-#endif
- // Disable text labels
- mLabelPosition ->setEnabled( FALSE );
- mLabelSize ->setEnabled( FALSE );
- mLabelRotation ->setEnabled( FALSE );
- mLabelCut ->setEnabled( FALSE );
- mLabelHollow ->setEnabled( FALSE );
- mLabelHoleType ->setEnabled( FALSE );
- mLabelTwist ->setEnabled( FALSE );
- mLabelSkew ->setEnabled( FALSE );
- mLabelShear ->setEnabled( FALSE );
- mLabelTaper ->setEnabled( FALSE );
- mLabelRadiusOffset->setEnabled( FALSE );
- mLabelRevolutions->setEnabled( FALSE );
-
- getChildView("select_single")->setVisible( FALSE);
- getChildView("edit_object")->setVisible( TRUE);
- getChildView("edit_object")->setEnabled(FALSE);
-
- getChildView("scale_hole")->setEnabled(FALSE);
- getChildView("scale_taper")->setEnabled(FALSE);
- getChildView("advanced_cut")->setEnabled(FALSE);
- getChildView("advanced_dimple")->setEnabled(FALSE);
- getChildView("advanced_slice")->setVisible( FALSE);
-}
-
-//
-// Static functions
-//
-
-// static
-void LLPanelObject::onCommitLock(LLUICtrl *ctrl, void *data)
-{
- // Checkbox will have toggled itself
- LLPanelObject *self = (LLPanelObject *)data;
-
- if(self->mRootObject.isNull()) return;
-
- BOOL new_state = self->mCheckLock->get();
-
- LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, !new_state, PERM_MOVE | PERM_MODIFY);
-}
-
-// static
-void LLPanelObject::onCommitPosition( LLUICtrl* ctrl, void* userdata )
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
- BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ;
- self->sendPosition(btn_down);
-}
-
-// static
-void LLPanelObject::onCommitScale( LLUICtrl* ctrl, void* userdata )
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
- BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ;
- self->sendScale(btn_down);
-}
-
-// static
-void LLPanelObject::onCommitRotation( LLUICtrl* ctrl, void* userdata )
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
- BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ;
- self->sendRotation(btn_down);
-}
-
-// static
-void LLPanelObject::onCommitPhysics( LLUICtrl* ctrl, void* userdata )
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
- self->sendIsPhysical();
-}
-
-// static
-void LLPanelObject::onCommitTemporary( LLUICtrl* ctrl, void* userdata )
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
- self->sendIsTemporary();
-}
-
-// static
-void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata )
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
- self->sendIsPhantom();
-}
-
-// static
-void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata )
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
- self->sendCastShadows();
-}
-
-
-void LLPanelObject::onSelectSculpt(const LLSD& data)
-{
- LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
-
- if (mTextureCtrl)
- {
- mSculptTextureRevert = mTextureCtrl->getImageAssetID();
- }
-
- sendSculpt();
-}
-
-
-void LLPanelObject::onCommitSculpt( const LLSD& data )
-{
- sendSculpt();
-}
-
-BOOL LLPanelObject::onDropSculpt(LLInventoryItem* item)
-{
- LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
-
- if (mTextureCtrl)
- {
- LLUUID asset = item->getAssetUUID();
-
- mTextureCtrl->setImageAssetID(asset);
- mSculptTextureRevert = asset;
- }
-
- return TRUE;
-}
-
-
-void LLPanelObject::onCancelSculpt(const LLSD& data)
-{
- LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
- if(!mTextureCtrl)
- return;
-
- mTextureCtrl->setImageAssetID(mSculptTextureRevert);
-
- sendSculpt();
-}
-
-// static
-void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata)
-{
- LLPanelObject* self = (LLPanelObject*) userdata;
-
- self->sendSculpt();
-}
+/** + * @file llpanelobject.cpp + * @brief Object editing (position, scale, etc.) in the tools floater + * + * $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" + +// file include +#include "llpanelobject.h" + +// linden library includes +#include "lleconomy.h" +#include "llerror.h" +#include "llfontgl.h" +#include "llpermissionsflags.h" +#include "llstring.h" +#include "llvolume.h" +#include "m3math.h" + +// project includes +#include "llagent.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llcolorswatch.h" +#include "llcombobox.h" +#include "llfocusmgr.h" +#include "llmanipscale.h" +#include "llpreviewscript.h" +#include "llresmgr.h" +#include "llselectmgr.h" +#include "llspinctrl.h" +#include "lltexturectrl.h" +#include "lltextbox.h" +#include "lltool.h" +#include "lltoolcomp.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llviewerobject.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llvovolume.h" +#include "llworld.h" +#include "pipeline.h" +#include "llviewercontrol.h" +#include "lluictrlfactory.h" +//#include "llfirstuse.h" + +#include "lldrawpool.h" + +// +// Constants +// +enum { + MI_BOX, + MI_CYLINDER, + MI_PRISM, + MI_SPHERE, + MI_TORUS, + MI_TUBE, + MI_RING, + MI_SCULPT, + MI_NONE, + MI_VOLUME_COUNT +}; + +enum { + MI_HOLE_SAME, + MI_HOLE_CIRCLE, + MI_HOLE_SQUARE, + MI_HOLE_TRIANGLE, + MI_HOLE_COUNT +}; + +//static const std::string LEGACY_FULLBRIGHT_DESC =LLTrans::getString("Fullbright"); + +BOOL LLPanelObject::postBuild() +{ + setMouseOpaque(FALSE); + + //-------------------------------------------------------- + // Top + //-------------------------------------------------------- + + // Lock checkbox + mCheckLock = getChild<LLCheckBoxCtrl>("checkbox locked"); + childSetCommitCallback("checkbox locked",onCommitLock,this); + + // Physical checkbox + mCheckPhysics = getChild<LLCheckBoxCtrl>("Physical Checkbox Ctrl"); + childSetCommitCallback("Physical Checkbox Ctrl",onCommitPhysics,this); + + // Temporary checkbox + mCheckTemporary = getChild<LLCheckBoxCtrl>("Temporary Checkbox Ctrl"); + childSetCommitCallback("Temporary Checkbox Ctrl",onCommitTemporary,this); + + // Phantom checkbox + mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl"); + childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); + + + // Position + mLabelPosition = getChild<LLTextBox>("label position"); + mCtrlPosX = getChild<LLSpinCtrl>("Pos X"); + childSetCommitCallback("Pos X",onCommitPosition,this); + mCtrlPosY = getChild<LLSpinCtrl>("Pos Y"); + childSetCommitCallback("Pos Y",onCommitPosition,this); + mCtrlPosZ = getChild<LLSpinCtrl>("Pos Z"); + childSetCommitCallback("Pos Z",onCommitPosition,this); + + // Scale + mLabelSize = getChild<LLTextBox>("label size"); + mCtrlScaleX = getChild<LLSpinCtrl>("Scale X"); + childSetCommitCallback("Scale X",onCommitScale,this); + + // Scale Y + mCtrlScaleY = getChild<LLSpinCtrl>("Scale Y"); + childSetCommitCallback("Scale Y",onCommitScale,this); + + // Scale Z + mCtrlScaleZ = getChild<LLSpinCtrl>("Scale Z"); + childSetCommitCallback("Scale Z",onCommitScale,this); + + // Rotation + mLabelRotation = getChild<LLTextBox>("label rotation"); + mCtrlRotX = getChild<LLSpinCtrl>("Rot X"); + childSetCommitCallback("Rot X",onCommitRotation,this); + mCtrlRotY = getChild<LLSpinCtrl>("Rot Y"); + childSetCommitCallback("Rot Y",onCommitRotation,this); + mCtrlRotZ = getChild<LLSpinCtrl>("Rot Z"); + childSetCommitCallback("Rot Z",onCommitRotation,this); + + //-------------------------------------------------------- + + // Base Type + mComboBaseType = getChild<LLComboBox>("comboBaseType"); + childSetCommitCallback("comboBaseType",onCommitParametric,this); + + // Cut + mLabelCut = getChild<LLTextBox>("text cut"); + mSpinCutBegin = getChild<LLSpinCtrl>("cut begin"); + childSetCommitCallback("cut begin",onCommitParametric,this); + mSpinCutBegin->setValidateBeforeCommit( precommitValidate ); + mSpinCutEnd = getChild<LLSpinCtrl>("cut end"); + childSetCommitCallback("cut end",onCommitParametric,this); + mSpinCutEnd->setValidateBeforeCommit( &precommitValidate ); + + // Hollow / Skew + mLabelHollow = getChild<LLTextBox>("text hollow"); + mLabelSkew = getChild<LLTextBox>("text skew"); + mSpinHollow = getChild<LLSpinCtrl>("Scale 1"); + childSetCommitCallback("Scale 1",onCommitParametric,this); + mSpinHollow->setValidateBeforeCommit( &precommitValidate ); + mSpinSkew = getChild<LLSpinCtrl>("Skew"); + childSetCommitCallback("Skew",onCommitParametric,this); + mSpinSkew->setValidateBeforeCommit( &precommitValidate ); + mLabelHoleType = getChild<LLTextBox>("Hollow Shape"); + + // Hole Type + mComboHoleType = getChild<LLComboBox>("hole"); + childSetCommitCallback("hole",onCommitParametric,this); + + // Twist + mLabelTwist = getChild<LLTextBox>("text twist"); + mSpinTwistBegin = getChild<LLSpinCtrl>("Twist Begin"); + childSetCommitCallback("Twist Begin",onCommitParametric,this); + mSpinTwistBegin->setValidateBeforeCommit( precommitValidate ); + mSpinTwist = getChild<LLSpinCtrl>("Twist End"); + childSetCommitCallback("Twist End",onCommitParametric,this); + mSpinTwist->setValidateBeforeCommit( &precommitValidate ); + + // Scale + mSpinScaleX = getChild<LLSpinCtrl>("Taper Scale X"); + childSetCommitCallback("Taper Scale X",onCommitParametric,this); + mSpinScaleX->setValidateBeforeCommit( &precommitValidate ); + mSpinScaleY = getChild<LLSpinCtrl>("Taper Scale Y"); + childSetCommitCallback("Taper Scale Y",onCommitParametric,this); + mSpinScaleY->setValidateBeforeCommit( &precommitValidate ); + + // Shear + mLabelShear = getChild<LLTextBox>("text topshear"); + mSpinShearX = getChild<LLSpinCtrl>("Shear X"); + childSetCommitCallback("Shear X",onCommitParametric,this); + mSpinShearX->setValidateBeforeCommit( &precommitValidate ); + mSpinShearY = getChild<LLSpinCtrl>("Shear Y"); + childSetCommitCallback("Shear Y",onCommitParametric,this); + mSpinShearY->setValidateBeforeCommit( &precommitValidate ); + + // Path / Profile + mCtrlPathBegin = getChild<LLSpinCtrl>("Path Limit Begin"); + childSetCommitCallback("Path Limit Begin",onCommitParametric,this); + mCtrlPathBegin->setValidateBeforeCommit( &precommitValidate ); + mCtrlPathEnd = getChild<LLSpinCtrl>("Path Limit End"); + childSetCommitCallback("Path Limit End",onCommitParametric,this); + mCtrlPathEnd->setValidateBeforeCommit( &precommitValidate ); + + // Taper + mLabelTaper = getChild<LLTextBox>("text taper2"); + mSpinTaperX = getChild<LLSpinCtrl>("Taper X"); + childSetCommitCallback("Taper X",onCommitParametric,this); + mSpinTaperX->setValidateBeforeCommit( precommitValidate ); + mSpinTaperY = getChild<LLSpinCtrl>("Taper Y"); + childSetCommitCallback("Taper Y",onCommitParametric,this); + mSpinTaperY->setValidateBeforeCommit( precommitValidate ); + + // Radius Offset / Revolutions + mLabelRadiusOffset = getChild<LLTextBox>("text radius delta"); + mLabelRevolutions = getChild<LLTextBox>("text revolutions"); + mSpinRadiusOffset = getChild<LLSpinCtrl>("Radius Offset"); + childSetCommitCallback("Radius Offset",onCommitParametric,this); + mSpinRadiusOffset->setValidateBeforeCommit( &precommitValidate ); + mSpinRevolutions = getChild<LLSpinCtrl>("Revolutions"); + childSetCommitCallback("Revolutions",onCommitParametric,this); + mSpinRevolutions->setValidateBeforeCommit( &precommitValidate ); + + // Sculpt + mCtrlSculptTexture = getChild<LLTextureCtrl>("sculpt texture control"); + if (mCtrlSculptTexture) + { + mCtrlSculptTexture->setDefaultImageAssetID(LLUUID(SCULPT_DEFAULT_TEXTURE)); + mCtrlSculptTexture->setCommitCallback( boost::bind(&LLPanelObject::onCommitSculpt, this, _2 )); + mCtrlSculptTexture->setOnCancelCallback( boost::bind(&LLPanelObject::onCancelSculpt, this, _2 )); + mCtrlSculptTexture->setOnSelectCallback( boost::bind(&LLPanelObject::onSelectSculpt, this, _2 )); + mCtrlSculptTexture->setDropCallback( boost::bind(&LLPanelObject::onDropSculpt, this, _2 )); + // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode + mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + // Allow any texture to be used during non-immediate mode. + mCtrlSculptTexture->setNonImmediateFilterPermMask(PERM_NONE); + LLAggregatePermissions texture_perms; + if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms)) + { + BOOL can_copy = + texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || + texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL; + BOOL can_transfer = + texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || + texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL; + mCtrlSculptTexture->setCanApplyImmediately(can_copy && can_transfer); + } + else + { + mCtrlSculptTexture->setCanApplyImmediately(FALSE); + } + } + + mLabelSculptType = getChild<LLTextBox>("label sculpt type"); + mCtrlSculptType = getChild<LLComboBox>("sculpt type control"); + childSetCommitCallback("sculpt type control", onCommitSculptType, this); + mCtrlSculptMirror = getChild<LLCheckBoxCtrl>("sculpt mirror control"); + childSetCommitCallback("sculpt mirror control", onCommitSculptType, this); + mCtrlSculptInvert = getChild<LLCheckBoxCtrl>("sculpt invert control"); + childSetCommitCallback("sculpt invert control", onCommitSculptType, this); + + // Start with everyone disabled + clearCtrls(); + + return TRUE; +} + +LLPanelObject::LLPanelObject() +: LLPanel(), + mIsPhysical(FALSE), + mIsTemporary(FALSE), + mIsPhantom(FALSE), + mCastShadows(TRUE), + mSelectedType(MI_BOX), + mSculptTextureRevert(LLUUID::null), + mSculptTypeRevert(0) +{ +} + + +LLPanelObject::~LLPanelObject() +{ + // Children all cleaned up by default view destructor. +} + +void LLPanelObject::getState( ) +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); + LLViewerObject* root_objectp = objectp; + if(!objectp) + { + objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + // *FIX: shouldn't we just keep the child? + if (objectp) + { + LLViewerObject* parentp = objectp->getRootEdit(); + + if (parentp) + { + root_objectp = parentp; + } + else + { + root_objectp = objectp; + } + } + } + + LLVOVolume *volobjp = NULL; + if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + if( !objectp ) + { + //forfeit focus + if (gFocusMgr.childHasKeyboardFocus(this)) + { + gFocusMgr.setKeyboardFocus(NULL); + } + + // Disable all text input fields + clearCtrls(); + return; + } + + // can move or rotate only linked group with move permissions, or sub-object with move and modify perms + BOOL enable_move = objectp->permMove() && !objectp->isAttachment() && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts")); + BOOL enable_scale = objectp->permMove() && objectp->permModify(); + BOOL enable_rotate = objectp->permMove() && ( (objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts")); + + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )) + && (selected_count == 1); + + if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 1) + { + enable_move = FALSE; + enable_scale = FALSE; + enable_rotate = FALSE; + } + + LLVector3 vec; + if (enable_move) + { + vec = objectp->getPositionEdit(); + mCtrlPosX->set( vec.mV[VX] ); + mCtrlPosY->set( vec.mV[VY] ); + mCtrlPosZ->set( vec.mV[VZ] ); + } + else + { + mCtrlPosX->clear(); + mCtrlPosY->clear(); + mCtrlPosZ->clear(); + } + + + mLabelPosition->setEnabled( enable_move ); + mCtrlPosX->setEnabled(enable_move); + mCtrlPosY->setEnabled(enable_move); + mCtrlPosZ->setEnabled(enable_move); + + if (enable_scale) + { + vec = objectp->getScale(); + mCtrlScaleX->set( vec.mV[VX] ); + mCtrlScaleY->set( vec.mV[VY] ); + mCtrlScaleZ->set( vec.mV[VZ] ); + } + else + { + mCtrlScaleX->clear(); + mCtrlScaleY->clear(); + mCtrlScaleZ->clear(); + } + + mLabelSize->setEnabled( enable_scale ); + mCtrlScaleX->setEnabled( enable_scale ); + mCtrlScaleY->setEnabled( enable_scale ); + mCtrlScaleZ->setEnabled( enable_scale ); + + LLQuaternion object_rot = objectp->getRotationEdit(); + object_rot.getEulerAngles(&(mCurEulerDegrees.mV[VX]), &(mCurEulerDegrees.mV[VY]), &(mCurEulerDegrees.mV[VZ])); + mCurEulerDegrees *= RAD_TO_DEG; + mCurEulerDegrees.mV[VX] = fmod(llround(mCurEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mCurEulerDegrees.mV[VY] = fmod(llround(mCurEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mCurEulerDegrees.mV[VZ] = fmod(llround(mCurEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + + if (enable_rotate) + { + mCtrlRotX->set( mCurEulerDegrees.mV[VX] ); + mCtrlRotY->set( mCurEulerDegrees.mV[VY] ); + mCtrlRotZ->set( mCurEulerDegrees.mV[VZ] ); + } + else + { + mCtrlRotX->clear(); + mCtrlRotY->clear(); + mCtrlRotZ->clear(); + } + + mLabelRotation->setEnabled( enable_rotate ); + mCtrlRotX->setEnabled( enable_rotate ); + mCtrlRotY->setEnabled( enable_rotate ); + mCtrlRotZ->setEnabled( enable_rotate ); + + BOOL owners_identical; + LLUUID owner_id; + std::string owner_name; + owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); + + // BUG? Check for all objects being editable? + S32 roots_selected = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount(); + BOOL editable = root_objectp->permModify(); + + // Select Single Message + getChildView("select_single")->setVisible( FALSE); + getChildView("edit_object")->setVisible( FALSE); + if (!editable || single_volume || selected_count <= 1) + { + getChildView("edit_object")->setVisible( TRUE); + getChildView("edit_object")->setEnabled(TRUE); + } + else + { + getChildView("select_single")->setVisible( TRUE); + getChildView("select_single")->setEnabled(TRUE); + } + // Lock checkbox - only modifiable if you own the object. + BOOL self_owned = (gAgent.getID() == owner_id); + mCheckLock->setEnabled( roots_selected > 0 && self_owned ); + + // More lock and debit checkbox - get the values + BOOL valid; + U32 owner_mask_on; + U32 owner_mask_off; + valid = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER, &owner_mask_on, &owner_mask_off); + + if(valid) + { + if(owner_mask_on & PERM_MOVE) + { + // owner can move, so not locked + mCheckLock->set(FALSE); + mCheckLock->setTentative(FALSE); + } + else if(owner_mask_off & PERM_MOVE) + { + // owner can't move, so locked + mCheckLock->set(TRUE); + mCheckLock->setTentative(FALSE); + } + else + { + // some locked, some not locked + mCheckLock->set(FALSE); + mCheckLock->setTentative(TRUE); + } + } + + BOOL is_flexible = volobjp && volobjp->isFlexible(); + + // Physics checkbox + mIsPhysical = root_objectp->usePhysics(); + mCheckPhysics->set( mIsPhysical ); + mCheckPhysics->setEnabled( roots_selected>0 + && (editable || gAgent.isGodlike()) + && !is_flexible); + + mIsTemporary = root_objectp->flagTemporaryOnRez(); + mCheckTemporary->set( mIsTemporary ); + mCheckTemporary->setEnabled( roots_selected>0 && editable ); + + mIsPhantom = root_objectp->flagPhantom(); + mCheckPhantom->set( mIsPhantom ); + mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible ); + + +#if 0 // 1.9.2 + mCastShadows = root_objectp->flagCastShadows(); + mCheckCastShadows->set( mCastShadows ); + mCheckCastShadows->setEnabled( roots_selected==1 && editable ); +#endif + + //---------------------------------------------------------------------------- + + S32 selected_item = MI_BOX; + S32 selected_hole = MI_HOLE_SAME; + BOOL enabled = FALSE; + BOOL hole_enabled = FALSE; + F32 scale_x=1.f, scale_y=1.f; + BOOL isMesh = FALSE; + + if( !objectp || !objectp->getVolume() || !editable || !single_volume) + { + // Clear out all geometry fields. + mComboBaseType->clear(); + mSpinHollow->clear(); + mSpinCutBegin->clear(); + mSpinCutEnd->clear(); + mCtrlPathBegin->clear(); + mCtrlPathEnd->clear(); + mSpinScaleX->clear(); + mSpinScaleY->clear(); + mSpinTwist->clear(); + mSpinTwistBegin->clear(); + mComboHoleType->clear(); + mSpinShearX->clear(); + mSpinShearY->clear(); + mSpinTaperX->clear(); + mSpinTaperY->clear(); + mSpinRadiusOffset->clear(); + mSpinRevolutions->clear(); + mSpinSkew->clear(); + + mSelectedType = MI_NONE; + } + else + { + // Only allowed to change these parameters for objects + // that you have permissions on AND are not attachments. + enabled = root_objectp->permModify(); + + // Volume type + const LLVolumeParams &volume_params = objectp->getVolume()->getParams(); + U8 path = volume_params.getPathParams().getCurveType(); + U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); + U8 profile = profile_and_hole & LL_PCODE_PROFILE_MASK; + U8 hole = profile_and_hole & LL_PCODE_HOLE_MASK; + + // Scale goes first so we can differentiate between a sphere and a torus, + // which have the same profile and path types. + + // Scale + scale_x = volume_params.getRatioX(); + scale_y = volume_params.getRatioY(); + + BOOL linear_path = (path == LL_PCODE_PATH_LINE) || (path == LL_PCODE_PATH_FLEXIBLE); + if ( linear_path && profile == LL_PCODE_PROFILE_CIRCLE ) + { + selected_item = MI_CYLINDER; + } + else if ( linear_path && profile == LL_PCODE_PROFILE_SQUARE ) + { + selected_item = MI_BOX; + } + else if ( linear_path && profile == LL_PCODE_PROFILE_ISOTRI ) + { + selected_item = MI_PRISM; + } + else if ( linear_path && profile == LL_PCODE_PROFILE_EQUALTRI ) + { + selected_item = MI_PRISM; + } + else if ( linear_path && profile == LL_PCODE_PROFILE_RIGHTTRI ) + { + selected_item = MI_PRISM; + } + else if (path == LL_PCODE_PATH_FLEXIBLE) // shouldn't happen + { + selected_item = MI_CYLINDER; // reasonable default + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y > 0.75f) + { + selected_item = MI_SPHERE; + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y <= 0.75f) + { + selected_item = MI_TORUS; + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE_HALF) + { + selected_item = MI_SPHERE; + } + else if ( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_CIRCLE ) + { + // Spirals aren't supported. Make it into a sphere. JC + selected_item = MI_SPHERE; + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_EQUALTRI ) + { + selected_item = MI_RING; + } + else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_SQUARE && scale_y <= 0.75f) + { + selected_item = MI_TUBE; + } + else + { + llinfos << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << llendl; + selected_item = MI_BOX; + } + + + if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + { + selected_item = MI_SCULPT; + //LLFirstUse::useSculptedPrim(); + } + + + mComboBaseType ->setCurrentByIndex( selected_item ); + mSelectedType = selected_item; + + // Grab S path + F32 begin_s = volume_params.getBeginS(); + F32 end_s = volume_params.getEndS(); + + // Compute cut and advanced cut from S and T + F32 begin_t = volume_params.getBeginT(); + F32 end_t = volume_params.getEndT(); + + // Hollowness + F32 hollow = volume_params.getHollow(); + mSpinHollow->set( 100.f * hollow ); + + // All hollow objects allow a shape to be selected. + if (hollow > 0.f) + { + switch (hole) + { + case LL_PCODE_HOLE_CIRCLE: + selected_hole = MI_HOLE_CIRCLE; + break; + case LL_PCODE_HOLE_SQUARE: + selected_hole = MI_HOLE_SQUARE; + break; + case LL_PCODE_HOLE_TRIANGLE: + selected_hole = MI_HOLE_TRIANGLE; + break; + case LL_PCODE_HOLE_SAME: + default: + selected_hole = MI_HOLE_SAME; + break; + } + mComboHoleType->setCurrentByIndex( selected_hole ); + hole_enabled = enabled; + } + else + { + mComboHoleType->setCurrentByIndex( MI_HOLE_SAME ); + hole_enabled = FALSE; + } + + // Cut interpretation varies based on base object type + F32 cut_begin, cut_end, adv_cut_begin, adv_cut_end; + + if ( selected_item == MI_SPHERE || selected_item == MI_TORUS || + selected_item == MI_TUBE || selected_item == MI_RING ) + { + cut_begin = begin_t; + cut_end = end_t; + adv_cut_begin = begin_s; + adv_cut_end = end_s; + } + else + { + cut_begin = begin_s; + cut_end = end_s; + adv_cut_begin = begin_t; + adv_cut_end = end_t; + } + + mSpinCutBegin ->set( cut_begin ); + mSpinCutEnd ->set( cut_end ); + mCtrlPathBegin ->set( adv_cut_begin ); + mCtrlPathEnd ->set( adv_cut_end ); + + // Twist + F32 twist = volume_params.getTwist(); + F32 twist_begin = volume_params.getTwistBegin(); + // Check the path type for conversion. + if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE) + { + twist *= OBJECT_TWIST_LINEAR_MAX; + twist_begin *= OBJECT_TWIST_LINEAR_MAX; + } + else + { + twist *= OBJECT_TWIST_MAX; + twist_begin *= OBJECT_TWIST_MAX; + } + + mSpinTwist ->set( twist ); + mSpinTwistBegin ->set( twist_begin ); + + // Shear + F32 shear_x = volume_params.getShearX(); + F32 shear_y = volume_params.getShearY(); + mSpinShearX->set( shear_x ); + mSpinShearY->set( shear_y ); + + // Taper + F32 taper_x = volume_params.getTaperX(); + F32 taper_y = volume_params.getTaperY(); + mSpinTaperX->set( taper_x ); + mSpinTaperY->set( taper_y ); + + // Radius offset. + F32 radius_offset = volume_params.getRadiusOffset(); + // Limit radius offset, based on taper and hole size y. + F32 radius_mag = fabs(radius_offset); + F32 hole_y_mag = fabs(scale_y); + F32 taper_y_mag = fabs(taper_y); + // Check to see if the taper effects us. + if ( (radius_offset > 0.f && taper_y < 0.f) || + (radius_offset < 0.f && taper_y > 0.f) ) + { + // The taper does not help increase the radius offset range. + taper_y_mag = 0.f; + } + F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); + // Enforce the maximum magnitude. + if (radius_mag > max_radius_mag) + { + // Check radius offset sign. + if (radius_offset < 0.f) + { + radius_offset = -max_radius_mag; + } + else + { + radius_offset = max_radius_mag; + } + } + mSpinRadiusOffset->set( radius_offset); + + // Revolutions + F32 revolutions = volume_params.getRevolutions(); + mSpinRevolutions->set( revolutions ); + + // Skew + F32 skew = volume_params.getSkew(); + // Limit skew, based on revolutions hole size x. + F32 skew_mag= fabs(skew); + F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); + // Discontinuity; A revolution of 1 allows skews below 0.5. + if ( fabs(revolutions - 1.0f) < 0.001) + min_skew_mag = 0.0f; + + // Clip skew. + if (skew_mag < min_skew_mag) + { + // Check skew sign. + if (skew < 0.0f) + { + skew = -min_skew_mag; + } + else + { + skew = min_skew_mag; + } + } + mSpinSkew->set( skew ); + } + + // Compute control visibility, label names, and twist range. + // Start with defaults. + BOOL cut_visible = TRUE; + BOOL hollow_visible = TRUE; + BOOL top_size_x_visible = TRUE; + BOOL top_size_y_visible = TRUE; + BOOL top_shear_x_visible = TRUE; + BOOL top_shear_y_visible = TRUE; + BOOL twist_visible = TRUE; + BOOL advanced_cut_visible = FALSE; + BOOL taper_visible = FALSE; + BOOL skew_visible = FALSE; + BOOL radius_offset_visible = FALSE; + BOOL revolutions_visible = FALSE; + BOOL sculpt_texture_visible = FALSE; + F32 twist_min = OBJECT_TWIST_LINEAR_MIN; + F32 twist_max = OBJECT_TWIST_LINEAR_MAX; + F32 twist_inc = OBJECT_TWIST_LINEAR_INC; + + BOOL advanced_is_dimple = FALSE; + BOOL advanced_is_slice = FALSE; + BOOL size_is_hole = FALSE; + + // Tune based on overall volume type + switch (selected_item) + { + case MI_SPHERE: + top_size_x_visible = FALSE; + top_size_y_visible = FALSE; + top_shear_x_visible = FALSE; + top_shear_y_visible = FALSE; + //twist_visible = FALSE; + advanced_cut_visible = TRUE; + advanced_is_dimple = TRUE; + twist_min = OBJECT_TWIST_MIN; + twist_max = OBJECT_TWIST_MAX; + twist_inc = OBJECT_TWIST_INC; + break; + + case MI_TORUS: + case MI_TUBE: + case MI_RING: + //top_size_x_visible = FALSE; + //top_size_y_visible = FALSE; + size_is_hole = TRUE; + skew_visible = TRUE; + advanced_cut_visible = TRUE; + taper_visible = TRUE; + radius_offset_visible = TRUE; + revolutions_visible = TRUE; + twist_min = OBJECT_TWIST_MIN; + twist_max = OBJECT_TWIST_MAX; + twist_inc = OBJECT_TWIST_INC; + + break; + + case MI_SCULPT: + cut_visible = FALSE; + hollow_visible = FALSE; + twist_visible = FALSE; + top_size_x_visible = FALSE; + top_size_y_visible = FALSE; + top_shear_x_visible = FALSE; + top_shear_y_visible = FALSE; + skew_visible = FALSE; + advanced_cut_visible = FALSE; + taper_visible = FALSE; + radius_offset_visible = FALSE; + revolutions_visible = FALSE; + sculpt_texture_visible = TRUE; + + break; + + case MI_BOX: + advanced_cut_visible = TRUE; + advanced_is_slice = TRUE; + break; + + case MI_CYLINDER: + advanced_cut_visible = TRUE; + advanced_is_slice = TRUE; + break; + + case MI_PRISM: + advanced_cut_visible = TRUE; + advanced_is_slice = TRUE; + break; + + default: + break; + } + + // Check if we need to change top size/hole size params. + switch (selected_item) + { + case MI_SPHERE: + case MI_TORUS: + case MI_TUBE: + case MI_RING: + mSpinScaleX->set( scale_x ); + mSpinScaleY->set( scale_y ); + mSpinScaleX->setMinValue(OBJECT_MIN_HOLE_SIZE); + mSpinScaleX->setMaxValue(OBJECT_MAX_HOLE_SIZE_X); + mSpinScaleY->setMinValue(OBJECT_MIN_HOLE_SIZE); + mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y); + break; + default: + if (editable) + { + mSpinScaleX->set( 1.f - scale_x ); + mSpinScaleY->set( 1.f - scale_y ); + mSpinScaleX->setMinValue(-1.f); + mSpinScaleX->setMaxValue(1.f); + mSpinScaleY->setMinValue(-1.f); + mSpinScaleY->setMaxValue(1.f); + } + break; + } + + // Check if we need to limit the hollow based on the hole type. + if ( selected_hole == MI_HOLE_SQUARE && + ( selected_item == MI_CYLINDER || selected_item == MI_TORUS || + selected_item == MI_PRISM || selected_item == MI_RING || + selected_item == MI_SPHERE ) ) + { + mSpinHollow->setMinValue(0.f); + mSpinHollow->setMaxValue(70.f); + } + else + { + mSpinHollow->setMinValue(0.f); + mSpinHollow->setMaxValue(95.f); + } + + // Update field enablement + mComboBaseType ->setEnabled( enabled ); + + mLabelCut ->setEnabled( enabled ); + mSpinCutBegin ->setEnabled( enabled ); + mSpinCutEnd ->setEnabled( enabled ); + + mLabelHollow ->setEnabled( enabled ); + mSpinHollow ->setEnabled( enabled ); + mLabelHoleType ->setEnabled( hole_enabled ); + mComboHoleType ->setEnabled( hole_enabled ); + + mLabelTwist ->setEnabled( enabled ); + mSpinTwist ->setEnabled( enabled ); + mSpinTwistBegin ->setEnabled( enabled ); + + mLabelSkew ->setEnabled( enabled ); + mSpinSkew ->setEnabled( enabled ); + + getChildView("scale_hole")->setVisible( FALSE); + getChildView("scale_taper")->setVisible( FALSE); + if (top_size_x_visible || top_size_y_visible) + { + if (size_is_hole) + { + getChildView("scale_hole")->setVisible( TRUE); + getChildView("scale_hole")->setEnabled(enabled); + } + else + { + getChildView("scale_taper")->setVisible( TRUE); + getChildView("scale_taper")->setEnabled(enabled); + } + } + + mSpinScaleX ->setEnabled( enabled ); + mSpinScaleY ->setEnabled( enabled ); + + mLabelShear ->setEnabled( enabled ); + mSpinShearX ->setEnabled( enabled ); + mSpinShearY ->setEnabled( enabled ); + + getChildView("advanced_cut")->setVisible( FALSE); + getChildView("advanced_dimple")->setVisible( FALSE); + getChildView("advanced_slice")->setVisible( FALSE); + + if (advanced_cut_visible) + { + if (advanced_is_dimple) + { + getChildView("advanced_dimple")->setVisible( TRUE); + getChildView("advanced_dimple")->setEnabled(enabled); + } + + else if (advanced_is_slice) + { + getChildView("advanced_slice")->setVisible( TRUE); + getChildView("advanced_slice")->setEnabled(enabled); + } + else + { + getChildView("advanced_cut")->setVisible( TRUE); + getChildView("advanced_cut")->setEnabled(enabled); + } + } + + mCtrlPathBegin ->setEnabled( enabled ); + mCtrlPathEnd ->setEnabled( enabled ); + + mLabelTaper ->setEnabled( enabled ); + mSpinTaperX ->setEnabled( enabled ); + mSpinTaperY ->setEnabled( enabled ); + + mLabelRadiusOffset->setEnabled( enabled ); + mSpinRadiusOffset ->setEnabled( enabled ); + + mLabelRevolutions->setEnabled( enabled ); + mSpinRevolutions ->setEnabled( enabled ); + + // Update field visibility + mLabelCut ->setVisible( cut_visible ); + mSpinCutBegin ->setVisible( cut_visible ); + mSpinCutEnd ->setVisible( cut_visible ); + + mLabelHollow ->setVisible( hollow_visible ); + mSpinHollow ->setVisible( hollow_visible ); + mLabelHoleType ->setVisible( hollow_visible ); + mComboHoleType ->setVisible( hollow_visible ); + + mLabelTwist ->setVisible( twist_visible ); + mSpinTwist ->setVisible( twist_visible ); + mSpinTwistBegin ->setVisible( twist_visible ); + mSpinTwist ->setMinValue( twist_min ); + mSpinTwist ->setMaxValue( twist_max ); + mSpinTwist ->setIncrement( twist_inc ); + mSpinTwistBegin ->setMinValue( twist_min ); + mSpinTwistBegin ->setMaxValue( twist_max ); + mSpinTwistBegin ->setIncrement( twist_inc ); + + mSpinScaleX ->setVisible( top_size_x_visible ); + mSpinScaleY ->setVisible( top_size_y_visible ); + + mLabelSkew ->setVisible( skew_visible ); + mSpinSkew ->setVisible( skew_visible ); + + mLabelShear ->setVisible( top_shear_x_visible || top_shear_y_visible ); + mSpinShearX ->setVisible( top_shear_x_visible ); + mSpinShearY ->setVisible( top_shear_y_visible ); + + mCtrlPathBegin ->setVisible( advanced_cut_visible ); + mCtrlPathEnd ->setVisible( advanced_cut_visible ); + + mLabelTaper ->setVisible( taper_visible ); + mSpinTaperX ->setVisible( taper_visible ); + mSpinTaperY ->setVisible( taper_visible ); + + mLabelRadiusOffset->setVisible( radius_offset_visible ); + mSpinRadiusOffset ->setVisible( radius_offset_visible ); + + mLabelRevolutions->setVisible( revolutions_visible ); + mSpinRevolutions ->setVisible( revolutions_visible ); + + mCtrlSculptTexture->setVisible(sculpt_texture_visible); + mLabelSculptType->setVisible(sculpt_texture_visible); + mCtrlSculptType->setVisible(sculpt_texture_visible); + + + // sculpt texture + if (selected_item == MI_SCULPT) + { + + + LLUUID id; + LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + + + if (sculpt_params) // if we have a legal sculpt param block for this object: + { + if (mObject != objectp) // we've just selected a new object, so save for undo + { + mSculptTextureRevert = sculpt_params->getSculptTexture(); + mSculptTypeRevert = sculpt_params->getSculptType(); + } + + U8 sculpt_type = sculpt_params->getSculptType(); + U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK; + BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT; + BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR; + isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH); + + LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control"); + if(mTextureCtrl) + { + mTextureCtrl->setTentative(FALSE); + mTextureCtrl->setEnabled(editable && !isMesh); + if (editable) + mTextureCtrl->setImageAssetID(sculpt_params->getSculptTexture()); + else + mTextureCtrl->setImageAssetID(LLUUID::null); + } + + mComboBaseType->setEnabled(!isMesh); + + if (mCtrlSculptType) + { + mCtrlSculptType->setCurrentByIndex(sculpt_stitching); + mCtrlSculptType->setEnabled(editable && !isMesh); + } + + if (mCtrlSculptMirror) + { + mCtrlSculptMirror->set(sculpt_mirror); + mCtrlSculptMirror->setEnabled(editable && !isMesh); + } + + if (mCtrlSculptInvert) + { + mCtrlSculptInvert->set(sculpt_invert); + mCtrlSculptInvert->setEnabled(editable); + } + + if (mLabelSculptType) + { + mLabelSculptType->setEnabled(TRUE); + } + + } + } + else + { + mSculptTextureRevert = LLUUID::null; + } + + mCtrlSculptMirror->setVisible(sculpt_texture_visible && !isMesh); + mCtrlSculptInvert->setVisible(sculpt_texture_visible && !isMesh); + + //---------------------------------------------------------------------------- + + mObject = objectp; + mRootObject = root_objectp; +} + +// static +bool LLPanelObject::precommitValidate( const LLSD& data ) +{ + // TODO: Richard will fill this in later. + return TRUE; // FALSE means that validation failed and new value should not be commited. +} + +void LLPanelObject::sendIsPhysical() +{ + BOOL value = mCheckPhysics->get(); + if( mIsPhysical != value ) + { + LLSelectMgr::getInstance()->selectionUpdatePhysics(value); + mIsPhysical = value; + + llinfos << "update physics sent" << llendl; + } + else + { + llinfos << "update physics not changed" << llendl; + } +} + +void LLPanelObject::sendIsTemporary() +{ + BOOL value = mCheckTemporary->get(); + if( mIsTemporary != value ) + { + LLSelectMgr::getInstance()->selectionUpdateTemporary(value); + mIsTemporary = value; + + llinfos << "update temporary sent" << llendl; + } + else + { + llinfos << "update temporary not changed" << llendl; + } +} + + +void LLPanelObject::sendIsPhantom() +{ + BOOL value = mCheckPhantom->get(); + if( mIsPhantom != value ) + { + LLSelectMgr::getInstance()->selectionUpdatePhantom(value); + mIsPhantom = value; + + llinfos << "update phantom sent" << llendl; + } + else + { + llinfos << "update phantom not changed" << llendl; + } +} + +void LLPanelObject::sendCastShadows() +{ + BOOL value = mCheckCastShadows->get(); + if( mCastShadows != value ) + { + LLSelectMgr::getInstance()->selectionUpdateCastShadows(value); + mCastShadows = value; + + llinfos << "update cast shadows sent" << llendl; + } + else + { + llinfos << "update cast shadows not changed" << llendl; + } +} + +// static +void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + + if (self->mObject.isNull()) + { + return; + } + + if (self->mObject->getPCode() != LL_PCODE_VOLUME) + { + // Don't allow modification of non-volume objects. + return; + } + + LLVolume *volume = self->mObject->getVolume(); + if (!volume) + { + return; + } + + LLVolumeParams volume_params; + self->getVolumeParams(volume_params); + + + + // set sculpting + S32 selected_type = self->mComboBaseType->getCurrentIndex(); + + if (selected_type == MI_SCULPT) + { + self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, TRUE, TRUE); + LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if (sculpt_params) + volume_params.setSculptID(sculpt_params->getSculptTexture(), sculpt_params->getSculptType()); + } + else + { + LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if (sculpt_params) + self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); + } + + // Update the volume, if necessary. + self->mObject->updateVolume(volume_params); + + + // This was added to make sure thate when changes are made, the UI + // adjusts to present valid options. + // *FIX: only some changes, ie, hollow or primitive type changes, + // require a refresh. + self->refresh(); + +} + +void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params) +{ + // Figure out what type of volume to make + S32 was_selected_type = mSelectedType; + S32 selected_type = mComboBaseType->getCurrentIndex(); + U8 profile; + U8 path; + switch ( selected_type ) + { + case MI_CYLINDER: + profile = LL_PCODE_PROFILE_CIRCLE; + path = LL_PCODE_PATH_LINE; + break; + + case MI_BOX: + profile = LL_PCODE_PROFILE_SQUARE; + path = LL_PCODE_PATH_LINE; + break; + + case MI_PRISM: + profile = LL_PCODE_PROFILE_EQUALTRI; + path = LL_PCODE_PATH_LINE; + break; + + case MI_SPHERE: + profile = LL_PCODE_PROFILE_CIRCLE_HALF; + path = LL_PCODE_PATH_CIRCLE; + break; + + case MI_TORUS: + profile = LL_PCODE_PROFILE_CIRCLE; + path = LL_PCODE_PATH_CIRCLE; + break; + + case MI_TUBE: + profile = LL_PCODE_PROFILE_SQUARE; + path = LL_PCODE_PATH_CIRCLE; + break; + + case MI_RING: + profile = LL_PCODE_PROFILE_EQUALTRI; + path = LL_PCODE_PATH_CIRCLE; + break; + + case MI_SCULPT: + profile = LL_PCODE_PROFILE_CIRCLE; + path = LL_PCODE_PATH_CIRCLE; + break; + + default: + llwarns << "Unknown base type " << selected_type + << " in getVolumeParams()" << llendl; + // assume a box + selected_type = MI_BOX; + profile = LL_PCODE_PROFILE_SQUARE; + path = LL_PCODE_PATH_LINE; + break; + } + + + if (path == LL_PCODE_PATH_LINE) + { + LLVOVolume *volobjp = (LLVOVolume *)(LLViewerObject*)(mObject); + if (volobjp->isFlexible()) + { + path = LL_PCODE_PATH_FLEXIBLE; + } + } + + S32 selected_hole = mComboHoleType->getCurrentIndex(); + U8 hole; + switch (selected_hole) + { + case MI_HOLE_CIRCLE: + hole = LL_PCODE_HOLE_CIRCLE; + break; + case MI_HOLE_SQUARE: + hole = LL_PCODE_HOLE_SQUARE; + break; + case MI_HOLE_TRIANGLE: + hole = LL_PCODE_HOLE_TRIANGLE; + break; + case MI_HOLE_SAME: + default: + hole = LL_PCODE_HOLE_SAME; + break; + } + + volume_params.setType(profile | hole, path); + mSelectedType = selected_type; + + // Compute cut start/end + F32 cut_begin = mSpinCutBegin->get(); + F32 cut_end = mSpinCutEnd->get(); + + // Make sure at least OBJECT_CUT_INC of the object survives + if (cut_begin > cut_end - OBJECT_MIN_CUT_INC) + { + cut_begin = cut_end - OBJECT_MIN_CUT_INC; + mSpinCutBegin->set(cut_begin); + } + + F32 adv_cut_begin = mCtrlPathBegin->get(); + F32 adv_cut_end = mCtrlPathEnd->get(); + + // Make sure at least OBJECT_CUT_INC of the object survives + if (adv_cut_begin > adv_cut_end - OBJECT_MIN_CUT_INC) + { + adv_cut_begin = adv_cut_end - OBJECT_MIN_CUT_INC; + mCtrlPathBegin->set(adv_cut_begin); + } + + F32 begin_s, end_s; + F32 begin_t, end_t; + + if (selected_type == MI_SPHERE || selected_type == MI_TORUS || + selected_type == MI_TUBE || selected_type == MI_RING) + { + begin_s = adv_cut_begin; + end_s = adv_cut_end; + + begin_t = cut_begin; + end_t = cut_end; + } + else + { + begin_s = cut_begin; + end_s = cut_end; + + begin_t = adv_cut_begin; + end_t = adv_cut_end; + } + + volume_params.setBeginAndEndS(begin_s, end_s); + volume_params.setBeginAndEndT(begin_t, end_t); + + // Hollowness + F32 hollow = mSpinHollow->get() / 100.f; + + if ( selected_hole == MI_HOLE_SQUARE && + ( selected_type == MI_CYLINDER || selected_type == MI_TORUS || + selected_type == MI_PRISM || selected_type == MI_RING || + selected_type == MI_SPHERE ) ) + { + if (hollow > 0.7f) hollow = 0.7f; + } + + volume_params.setHollow( hollow ); + + // Twist Begin,End + F32 twist_begin = mSpinTwistBegin->get(); + F32 twist = mSpinTwist->get(); + // Check the path type for twist conversion. + if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE) + { + twist_begin /= OBJECT_TWIST_LINEAR_MAX; + twist /= OBJECT_TWIST_LINEAR_MAX; + } + else + { + twist_begin /= OBJECT_TWIST_MAX; + twist /= OBJECT_TWIST_MAX; + } + + volume_params.setTwistBegin(twist_begin); + volume_params.setTwist(twist); + + // Scale X,Y + F32 scale_x = mSpinScaleX->get(); + F32 scale_y = mSpinScaleY->get(); + if ( was_selected_type == MI_BOX || was_selected_type == MI_CYLINDER || was_selected_type == MI_PRISM) + { + scale_x = 1.f - scale_x; + scale_y = 1.f - scale_y; + } + + // Skew + F32 skew = mSpinSkew->get(); + + // Taper X,Y + F32 taper_x = mSpinTaperX->get(); + F32 taper_y = mSpinTaperY->get(); + + // Radius offset + F32 radius_offset = mSpinRadiusOffset->get(); + + // Revolutions + F32 revolutions = mSpinRevolutions->get(); + + if ( selected_type == MI_SPHERE ) + { + // Snap values to valid sphere parameters. + scale_x = 1.0f; + scale_y = 1.0f; + skew = 0.0f; + taper_x = 0.0f; + taper_y = 0.0f; + radius_offset = 0.0f; + revolutions = 1.0f; + } + else if ( selected_type == MI_TORUS || selected_type == MI_TUBE || + selected_type == MI_RING ) + { + scale_x = llclamp( + scale_x, + OBJECT_MIN_HOLE_SIZE, + OBJECT_MAX_HOLE_SIZE_X); + scale_y = llclamp( + scale_y, + OBJECT_MIN_HOLE_SIZE, + OBJECT_MAX_HOLE_SIZE_Y); + + // Limit radius offset, based on taper and hole size y. + F32 radius_mag = fabs(radius_offset); + F32 hole_y_mag = fabs(scale_y); + F32 taper_y_mag = fabs(taper_y); + // Check to see if the taper effects us. + if ( (radius_offset > 0.f && taper_y < 0.f) || + (radius_offset < 0.f && taper_y > 0.f) ) + { + // The taper does not help increase the radius offset range. + taper_y_mag = 0.f; + } + F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag); + // Enforce the maximum magnitude. + if (radius_mag > max_radius_mag) + { + // Check radius offset sign. + if (radius_offset < 0.f) + { + radius_offset = -max_radius_mag; + } + else + { + radius_offset = max_radius_mag; + } + } + + // Check the skew value against the revolutions. + F32 skew_mag= fabs(skew); + F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f); + // Discontinuity; A revolution of 1 allows skews below 0.5. + if ( fabs(revolutions - 1.0f) < 0.001) + min_skew_mag = 0.0f; + + // Clip skew. + if (skew_mag < min_skew_mag) + { + // Check skew sign. + if (skew < 0.0f) + { + skew = -min_skew_mag; + } + else + { + skew = min_skew_mag; + } + } + } + + volume_params.setRatio( scale_x, scale_y ); + volume_params.setSkew(skew); + volume_params.setTaper( taper_x, taper_y ); + volume_params.setRadiusOffset(radius_offset); + volume_params.setRevolutions(revolutions); + + // Shear X,Y + F32 shear_x = mSpinShearX->get(); + F32 shear_y = mSpinShearY->get(); + volume_params.setShear( shear_x, shear_y ); + + if (selected_type == MI_SCULPT) + { + volume_params.setSculptID(LLUUID::null, 0); + volume_params.setBeginAndEndT (0, 1); + volume_params.setBeginAndEndS (0, 1); + volume_params.setHollow (0); + volume_params.setTwistBegin (0); + volume_params.setTwistEnd (0); + volume_params.setRatio (1, 0.5); + volume_params.setShear (0, 0); + volume_params.setTaper (0, 0); + volume_params.setRevolutions (1); + volume_params.setRadiusOffset (0); + volume_params.setSkew (0); + } + +} + +// BUG: Make work with multiple objects +void LLPanelObject::sendRotation(BOOL btn_down) +{ + if (mObject.isNull()) return; + + LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); + new_rot.mV[VX] = llround(new_rot.mV[VX], OBJECT_ROTATION_PRECISION); + new_rot.mV[VY] = llround(new_rot.mV[VY], OBJECT_ROTATION_PRECISION); + new_rot.mV[VZ] = llround(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION); + + // Note: must compare before conversion to radians + LLVector3 delta = new_rot - mCurEulerDegrees; + + if (delta.magVec() >= 0.0005f) + { + mCurEulerDegrees = new_rot; + new_rot *= DEG_TO_RAD; + + LLQuaternion rotation; + rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]); + + if (mRootObject != mObject) + { + rotation = rotation * ~mRootObject->getRotationRegion(); + } + std::vector<LLVector3>& child_positions = mObject->mUnselectedChildrenPositions ; + std::vector<LLQuaternion> child_rotations; + if (mObject->isRootEdit()) + { + mObject->saveUnselectedChildrenRotation(child_rotations) ; + mObject->saveUnselectedChildrenPosition(child_positions) ; + } + + mObject->setRotation(rotation); + LLManip::rebuild(mObject) ; + + // for individually selected roots, we need to counterrotate all the children + if (mObject->isRootEdit()) + { + mObject->resetChildrenRotationAndPosition(child_rotations, child_positions) ; + } + + if(!btn_down) + { + child_positions.clear() ; + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_ROTATION | UPD_POSITION); + } + } +} + + +// BUG: Make work with multiple objects +void LLPanelObject::sendScale(BOOL btn_down) +{ + if (mObject.isNull()) return; + + LLVector3 newscale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); + + LLVector3 delta = newscale - mObject->getScale(); + if (delta.magVec() >= 0.0005f) + { + // scale changed by more than 1/2 millimeter + + // check to see if we aren't scaling the textures + // (in which case the tex coord's need to be recomputed) + BOOL dont_stretch_textures = !LLManipScale::getStretchTextures(); + if (dont_stretch_textures) + { + LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE); + } + + mObject->setScale(newscale, TRUE); + + if(!btn_down) + { + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_SCALE | UPD_POSITION); + } + + LLSelectMgr::getInstance()->adjustTexturesByScale(TRUE, !dont_stretch_textures); +// llinfos << "scale sent" << llendl; + } + else + { +// llinfos << "scale not changed" << llendl; + } +} + + +void LLPanelObject::sendPosition(BOOL btn_down) +{ + if (mObject.isNull()) return; + + LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); + LLViewerRegion* regionp = mObject->getRegion(); + + // Clamp the Z height + const F32 height = newpos.mV[VZ]; + const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal()); + const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight(); + + if (!mObject->isAttachment()) + { + if ( height < min_height) + { + newpos.mV[VZ] = min_height; + mCtrlPosZ->set( min_height ); + } + else if ( height > max_height ) + { + newpos.mV[VZ] = max_height; + mCtrlPosZ->set( max_height ); + } + + // Grass is always drawn on the ground, so clamp its position to the ground + if (mObject->getPCode() == LL_PCODE_LEGACY_GRASS) + { + mCtrlPosZ->set(LLWorld::getInstance()->resolveLandHeightAgent(newpos) + 1.f); + } + } + + // Make sure new position is in a valid region, so the object + // won't get dumped by the simulator. + LLVector3d new_pos_global = regionp->getPosGlobalFromRegion(newpos); + + if ( LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global) ) + { + // send only if the position is changed, that is, the delta vector is not zero + LLVector3d old_pos_global = mObject->getPositionGlobal(); + LLVector3d delta = new_pos_global - old_pos_global; + // moved more than 1/2 millimeter + if (delta.magVec() >= 0.0005f) + { + if (mRootObject != mObject) + { + newpos = newpos - mRootObject->getPositionRegion(); + newpos = newpos * ~mRootObject->getRotationRegion(); + mObject->setPositionParent(newpos); + } + else + { + mObject->setPositionEdit(newpos); + } + + LLManip::rebuild(mObject) ; + + // for individually selected roots, we need to counter-translate all unselected children + if (mObject->isRootEdit()) + { + // only offset by parent's translation + mObject->resetChildrenPosition(LLVector3(-delta), TRUE) ; + } + + if(!btn_down) + { + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); + } + + LLSelectMgr::getInstance()->updateSelectionCenter(); + } + } + else + { + // move failed, so we update the UI with the correct values + LLVector3 vec = mRootObject->getPositionRegion(); + mCtrlPosX->set(vec.mV[VX]); + mCtrlPosY->set(vec.mV[VY]); + mCtrlPosZ->set(vec.mV[VZ]); + } +} + +void LLPanelObject::sendSculpt() +{ + if (mObject.isNull()) + return; + + LLSculptParams sculpt_params; + + if (mCtrlSculptTexture) + sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID()); + + U8 sculpt_type = 0; + + if (mCtrlSculptType) + sculpt_type |= mCtrlSculptType->getCurrentIndex(); + + bool enabled = sculpt_type != LL_SCULPT_TYPE_MESH; + + if (mCtrlSculptMirror) + { + mCtrlSculptMirror->setEnabled(enabled ? TRUE : FALSE); + } + if (mCtrlSculptInvert) + { + mCtrlSculptInvert->setEnabled(enabled ? TRUE : FALSE); + } + + if ((mCtrlSculptMirror) && (mCtrlSculptMirror->get())) + sculpt_type |= LL_SCULPT_FLAG_MIRROR; + + if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get())) + sculpt_type |= LL_SCULPT_FLAG_INVERT; + + sculpt_params.setSculptType(sculpt_type); + mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); +} + +void LLPanelObject::refresh() +{ + getState(); + if (mObject.notNull() && mObject->isDead()) + { + mObject = NULL; + } + + if (mRootObject.notNull() && mRootObject->isDead()) + { + mRootObject = NULL; + } + + bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + gAgent.getRegion() && + !gAgent.getRegion()->getCapability("GetMesh").empty(); + + F32 max_scale = get_default_max_prim_scale(LLPickInfo::isFlora(mObject)); + + getChild<LLSpinCtrl>("Scale X")->setMaxValue(max_scale); + getChild<LLSpinCtrl>("Scale Y")->setMaxValue(max_scale); + getChild<LLSpinCtrl>("Scale Z")->setMaxValue(max_scale); + + BOOL found = mCtrlSculptType->itemExists("Mesh"); + if (enable_mesh && !found) + { + mCtrlSculptType->add("Mesh"); + } + else if (!enable_mesh && found) + { + mCtrlSculptType->remove("Mesh"); + } +} + + +void LLPanelObject::draw() +{ + const LLColor4 white( 1.0f, 1.0f, 1.0f, 1); + const LLColor4 red( 1.0f, 0.25f, 0.f, 1); + const LLColor4 green( 0.f, 1.0f, 0.f, 1); + const LLColor4 blue( 0.f, 0.5f, 1.0f, 1); + + // Tune the colors of the labels + LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); + + if (tool == LLToolCompTranslate::getInstance()) + { + mCtrlPosX ->setLabelColor(red); + mCtrlPosY ->setLabelColor(green); + mCtrlPosZ ->setLabelColor(blue); + + mCtrlScaleX ->setLabelColor(white); + mCtrlScaleY ->setLabelColor(white); + mCtrlScaleZ ->setLabelColor(white); + + mCtrlRotX ->setLabelColor(white); + mCtrlRotY ->setLabelColor(white); + mCtrlRotZ ->setLabelColor(white); + } + else if ( tool == LLToolCompScale::getInstance() ) + { + mCtrlPosX ->setLabelColor(white); + mCtrlPosY ->setLabelColor(white); + mCtrlPosZ ->setLabelColor(white); + + mCtrlScaleX ->setLabelColor(red); + mCtrlScaleY ->setLabelColor(green); + mCtrlScaleZ ->setLabelColor(blue); + + mCtrlRotX ->setLabelColor(white); + mCtrlRotY ->setLabelColor(white); + mCtrlRotZ ->setLabelColor(white); + } + else if ( tool == LLToolCompRotate::getInstance() ) + { + mCtrlPosX ->setLabelColor(white); + mCtrlPosY ->setLabelColor(white); + mCtrlPosZ ->setLabelColor(white); + + mCtrlScaleX ->setLabelColor(white); + mCtrlScaleY ->setLabelColor(white); + mCtrlScaleZ ->setLabelColor(white); + + mCtrlRotX ->setLabelColor(red); + mCtrlRotY ->setLabelColor(green); + mCtrlRotZ ->setLabelColor(blue); + } + else + { + mCtrlPosX ->setLabelColor(white); + mCtrlPosY ->setLabelColor(white); + mCtrlPosZ ->setLabelColor(white); + + mCtrlScaleX ->setLabelColor(white); + mCtrlScaleY ->setLabelColor(white); + mCtrlScaleZ ->setLabelColor(white); + + mCtrlRotX ->setLabelColor(white); + mCtrlRotY ->setLabelColor(white); + mCtrlRotZ ->setLabelColor(white); + } + + LLPanel::draw(); +} + +// virtual +void LLPanelObject::clearCtrls() +{ + LLPanel::clearCtrls(); + + mCheckLock ->set(FALSE); + mCheckLock ->setEnabled( FALSE ); + mCheckPhysics ->set(FALSE); + mCheckPhysics ->setEnabled( FALSE ); + mCheckTemporary ->set(FALSE); + mCheckTemporary ->setEnabled( FALSE ); + mCheckPhantom ->set(FALSE); + mCheckPhantom ->setEnabled( FALSE ); + +#if 0 // 1.9.2 + mCheckCastShadows->set(FALSE); + mCheckCastShadows->setEnabled( FALSE ); +#endif + // Disable text labels + mLabelPosition ->setEnabled( FALSE ); + mLabelSize ->setEnabled( FALSE ); + mLabelRotation ->setEnabled( FALSE ); + mLabelCut ->setEnabled( FALSE ); + mLabelHollow ->setEnabled( FALSE ); + mLabelHoleType ->setEnabled( FALSE ); + mLabelTwist ->setEnabled( FALSE ); + mLabelSkew ->setEnabled( FALSE ); + mLabelShear ->setEnabled( FALSE ); + mLabelTaper ->setEnabled( FALSE ); + mLabelRadiusOffset->setEnabled( FALSE ); + mLabelRevolutions->setEnabled( FALSE ); + + getChildView("select_single")->setVisible( FALSE); + getChildView("edit_object")->setVisible( TRUE); + getChildView("edit_object")->setEnabled(FALSE); + + getChildView("scale_hole")->setEnabled(FALSE); + getChildView("scale_taper")->setEnabled(FALSE); + getChildView("advanced_cut")->setEnabled(FALSE); + getChildView("advanced_dimple")->setEnabled(FALSE); + getChildView("advanced_slice")->setVisible( FALSE); +} + +// +// Static functions +// + +// static +void LLPanelObject::onCommitLock(LLUICtrl *ctrl, void *data) +{ + // Checkbox will have toggled itself + LLPanelObject *self = (LLPanelObject *)data; + + if(self->mRootObject.isNull()) return; + + BOOL new_state = self->mCheckLock->get(); + + LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, !new_state, PERM_MOVE | PERM_MODIFY); +} + +// static +void LLPanelObject::onCommitPosition( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; + self->sendPosition(btn_down); +} + +// static +void LLPanelObject::onCommitScale( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; + self->sendScale(btn_down); +} + +// static +void LLPanelObject::onCommitRotation( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ; + self->sendRotation(btn_down); +} + +// static +void LLPanelObject::onCommitPhysics( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendIsPhysical(); +} + +// static +void LLPanelObject::onCommitTemporary( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendIsTemporary(); +} + +// static +void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendIsPhantom(); +} + +// static +void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + self->sendCastShadows(); +} + + +void LLPanelObject::onSelectSculpt(const LLSD& data) +{ + LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control"); + + if (mTextureCtrl) + { + mSculptTextureRevert = mTextureCtrl->getImageAssetID(); + } + + sendSculpt(); +} + + +void LLPanelObject::onCommitSculpt( const LLSD& data ) +{ + sendSculpt(); +} + +BOOL LLPanelObject::onDropSculpt(LLInventoryItem* item) +{ + LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control"); + + if (mTextureCtrl) + { + LLUUID asset = item->getAssetUUID(); + + mTextureCtrl->setImageAssetID(asset); + mSculptTextureRevert = asset; + } + + return TRUE; +} + + +void LLPanelObject::onCancelSculpt(const LLSD& data) +{ + LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control"); + if(!mTextureCtrl) + return; + + mTextureCtrl->setImageAssetID(mSculptTextureRevert); + + sendSculpt(); +} + +// static +void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata) +{ + LLPanelObject* self = (LLPanelObject*) userdata; + + self->sendSculpt(); +} diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 86b56df556..fdd1199b78 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5376,10 +5376,10 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) { // notification was specified using the new mechanism, so we can just handle it here std::string notificationID; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
- if (!LLNotifications::getInstance()->templateExists(notificationID))
- {
- return false;
+ msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); + if (!LLNotifications::getInstance()->templateExists(notificationID)) + { + return false; } std::string llsdRaw; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 929f3ad188..e7878d8adf 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1,5712 +1,5712 @@ -/**
- * @file llviewerobject.cpp
- * @brief Base class for viewer objects
- *
- * $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 "llviewerobject.h"
-
-#include "llaudioengine.h"
-#include "imageids.h"
-#include "indra_constants.h"
-#include "llmath.h"
-#include "llflexibleobject.h"
-#include "llviewercontrol.h"
-#include "lldatapacker.h"
-#include "llfasttimer.h"
-#include "llfloaterreg.h"
-#include "llfontgl.h"
-#include "llframetimer.h"
-#include "llinventory.h"
-#include "llinventorydefines.h"
-#include "llmaterialtable.h"
-#include "llmutelist.h"
-#include "llnamevalue.h"
-#include "llprimitive.h"
-#include "llquantize.h"
-#include "llregionhandle.h"
-#include "llsdserialize.h"
-#include "lltree_common.h"
-#include "llxfermanager.h"
-#include "message.h"
-#include "object_flags.h"
-#include "timing.h"
-
-#include "llaudiosourcevo.h"
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llbbox.h"
-#include "llbox.h"
-#include "llcylinder.h"
-#include "lldrawable.h"
-#include "llface.h"
-#include "llfloaterproperties.h"
-#include "llfloatertools.h"
-#include "llfollowcam.h"
-#include "llhudtext.h"
-#include "llselectmgr.h"
-#include "llrendersphere.h"
-#include "lltooldraganddrop.h"
-#include "llviewercamera.h"
-#include "llviewertexturelist.h"
-#include "llviewerinventory.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparceloverlay.h"
-#include "llviewerpartsource.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewertextureanim.h"
-#include "llviewerwindow.h" // For getSpinAxis
-#include "llvoavatar.h"
-#include "llvoavatarself.h"
-#include "llvoclouds.h"
-#include "llvograss.h"
-#include "llvoground.h"
-#include "llvolume.h"
-#include "llvolumemessage.h"
-#include "llvopartgroup.h"
-#include "llvosky.h"
-#include "llvosurfacepatch.h"
-#include "llvotextbubble.h"
-#include "llvotree.h"
-#include "llvovolume.h"
-#include "llvowater.h"
-#include "llworld.h"
-#include "llui.h"
-#include "pipeline.h"
-#include "llviewernetwork.h"
-#include "llvowlsky.h"
-#include "llmanip.h"
-#include "lltrans.h"
-#include "llsdutil.h"
-#include "llmediaentry.h"
-#include "llaccountingquota.h"
-
-//#define DEBUG_UPDATE_TYPE
-
-BOOL LLViewerObject::sVelocityInterpolate = TRUE;
-BOOL LLViewerObject::sPingInterpolate = TRUE;
-
-U32 LLViewerObject::sNumZombieObjects = 0;
-S32 LLViewerObject::sNumObjects = 0;
-BOOL LLViewerObject::sMapDebug = TRUE;
-LLColor4 LLViewerObject::sEditSelectColor( 1.0f, 1.f, 0.f, 0.3f); // Edit OK
-LLColor4 LLViewerObject::sNoEditSelectColor( 1.0f, 0.f, 0.f, 0.3f); // Can't edit
-S32 LLViewerObject::sAxisArrowLength(50);
-BOOL LLViewerObject::sPulseEnabled(FALSE);
-BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE
-
-// sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime
-F64 LLViewerObject::sMaxUpdateInterpolationTime = 3.0; // For motion interpolation: after X seconds with no updates, don't predict object motion
-F64 LLViewerObject::sPhaseOutUpdateInterpolationTime = 2.0; // For motion interpolation: after Y seconds with no updates, taper off motion prediction
-
-
-static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object");
-
-// static
-LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
-{
- LLViewerObject *res = NULL;
- LLFastTimer t1(FTM_CREATE_OBJECT);
-
- switch (pcode)
- {
- case LL_PCODE_VOLUME:
- res = new LLVOVolume(id, pcode, regionp); break;
- case LL_PCODE_LEGACY_AVATAR:
- {
- if (id == gAgentID)
- {
- if (!gAgentAvatarp)
- {
- gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp);
- }
- else
- {
- gAgentAvatarp->updateRegion(regionp);
- }
- res = gAgentAvatarp;
- }
- else
- {
- res = new LLVOAvatar(id, pcode, regionp);
- }
- static_cast<LLVOAvatar*>(res)->initInstance();
- break;
- }
- case LL_PCODE_LEGACY_GRASS:
- res = new LLVOGrass(id, pcode, regionp); break;
- case LL_PCODE_LEGACY_PART_SYS:
-// llwarns << "Creating old part sys!" << llendl;
-// res = new LLVOPart(id, pcode, regionp); break;
- res = NULL; break;
- case LL_PCODE_LEGACY_TREE:
- res = new LLVOTree(id, pcode, regionp); break;
- case LL_PCODE_TREE_NEW:
-// llwarns << "Creating new tree!" << llendl;
-// res = new LLVOTree(id, pcode, regionp); break;
- res = NULL; break;
- case LL_PCODE_LEGACY_TEXT_BUBBLE:
- res = new LLVOTextBubble(id, pcode, regionp); break;
- case LL_VO_CLOUDS:
- res = new LLVOClouds(id, pcode, regionp); break;
- case LL_VO_SURFACE_PATCH:
- res = new LLVOSurfacePatch(id, pcode, regionp); break;
- case LL_VO_SKY:
- res = new LLVOSky(id, pcode, regionp); break;
- case LL_VO_VOID_WATER:
- res = new LLVOVoidWater(id, pcode, regionp); break;
- case LL_VO_WATER:
- res = new LLVOWater(id, pcode, regionp); break;
- case LL_VO_GROUND:
- res = new LLVOGround(id, pcode, regionp); break;
- case LL_VO_PART_GROUP:
- res = new LLVOPartGroup(id, pcode, regionp); break;
- case LL_VO_HUD_PART_GROUP:
- res = new LLVOHUDPartGroup(id, pcode, regionp); break;
- case LL_VO_WL_SKY:
- res = new LLVOWLSky(id, pcode, regionp); break;
- default:
- llwarns << "Unknown object pcode " << (S32)pcode << llendl;
- res = NULL; break;
- }
- return res;
-}
-
-LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global)
-: LLPrimitive(),
- mChildList(),
- mID(id),
- mLocalID(0),
- mTotalCRC(0),
- mTEImages(NULL),
- mGLName(0),
- mbCanSelect(TRUE),
- mFlags(0),
- mPhysicsShapeType(0),
- mPhysicsGravity(0),
- mPhysicsFriction(0),
- mPhysicsDensity(0),
- mPhysicsRestitution(0),
- mDrawable(),
- mCreateSelected(FALSE),
- mRenderMedia(FALSE),
- mBestUpdatePrecision(0),
- mText(),
- mLastInterpUpdateSecs(0.f),
- mLastMessageUpdateSecs(0.f),
- mLatestRecvPacketID(0),
- mData(NULL),
- mAudioSourcep(NULL),
- mAudioGain(1.f),
- mAppAngle(0.f),
- mPixelArea(1024.f),
- mInventory(NULL),
- mInventorySerialNum(0),
- mRegionp( regionp ),
- mInventoryPending(FALSE),
- mInventoryDirty(FALSE),
- mDead(FALSE),
- mOrphaned(FALSE),
- mUserSelected(FALSE),
- mOnActiveList(FALSE),
- mOnMap(FALSE),
- mStatic(FALSE),
- mNumFaces(0),
- mTimeDilation(1.f),
- mRotTime(0.f),
- mJointInfo(NULL),
- mState(0),
- mMedia(NULL),
- mClickAction(0),
- mObjectCost(0),
- mLinksetCost(0),
- mPhysicsCost(0),
- mLinksetPhysicsCost(0.f),
- mCostStale(true),
- mPhysicsShapeUnknown(true),
- mAttachmentItemID(LLUUID::null),
- mLastUpdateType(OUT_UNKNOWN),
- mLastUpdateCached(FALSE)
-{
- if (!is_global)
- {
- llassert(mRegionp);
- }
-
- LLPrimitive::init_primitive(pcode);
-
- // CP: added 12/2/2005 - this was being initialised to 0, not the current frame time
- mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds();
-
- mPositionRegion = LLVector3(0.f, 0.f, 0.f);
-
- if (!is_global && mRegionp)
- {
- mPositionAgent = mRegionp->getOriginAgent();
- }
-
- LLViewerObject::sNumObjects++;
-}
-
-LLViewerObject::~LLViewerObject()
-{
- deleteTEImages();
-
- if(mInventory)
- {
- mInventory->clear(); // will deref and delete entries
- delete mInventory;
- mInventory = NULL;
- }
-
- if (mJointInfo)
- {
- delete mJointInfo;
- mJointInfo = NULL;
- }
-
- if (mPartSourcep)
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
-
- // Delete memory associated with extra parameters.
- std::map<U16, ExtraParameter*>::iterator iter;
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- if(iter->second != NULL)
- {
- delete iter->second->data;
- delete iter->second;
- }
- }
- mExtraParameterList.clear();
-
- for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ;
- mNameValuePairs.clear();
-
- delete[] mData;
- mData = NULL;
-
- delete mMedia;
- mMedia = NULL;
-
- sNumObjects--;
- sNumZombieObjects--;
- llassert(mChildList.size() == 0);
-
- clearInventoryListeners();
-}
-
-void LLViewerObject::deleteTEImages()
-{
- delete[] mTEImages;
- mTEImages = NULL;
-}
-
-void LLViewerObject::markDead()
-{
- if (!mDead)
- {
- //llinfos << "Marking self " << mLocalID << " as dead." << llendl;
-
- // Root object of this hierarchy unlinks itself.
- if (getParent())
- {
- ((LLViewerObject *)getParent())->removeChild(this);
- // go ahead and delete any jointinfo's that we find
- delete mJointInfo;
- mJointInfo = NULL;
- }
-
- // Mark itself as dead
- mDead = TRUE;
- gObjectList.cleanupReferences(this);
-
- LLViewerObject *childp;
- while (mChildList.size() > 0)
- {
- childp = mChildList.back();
- if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR)
- {
- //llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl;
- childp->setParent(NULL); // LLViewerObject::markDead 1
- childp->markDead();
- }
- else
- {
- // make sure avatar is no longer parented,
- // so we can properly set it's position
- childp->setDrawableParent(NULL);
- ((LLVOAvatar*)childp)->getOffObject();
- childp->setParent(NULL); // LLViewerObject::markDead 2
- }
- mChildList.pop_back();
- }
-
- if (mDrawable.notNull())
- {
- // Drawables are reference counted, mark as dead, then nuke the pointer.
- mDrawable->markDead();
- mDrawable = NULL;
- }
-
- if (mText)
- {
- mText->markDead();
- mText = NULL;
- }
-
- if (mIcon)
- {
- mIcon->markDead();
- mIcon = NULL;
- }
-
- if (mPartSourcep)
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
-
- if (mAudioSourcep)
- {
- // Do some cleanup
- if (gAudiop)
- {
- gAudiop->cleanupAudioSource(mAudioSourcep);
- }
- mAudioSourcep = NULL;
- }
-
- if (flagAnimSource())
- {
- if (isAgentAvatarValid())
- {
- // stop motions associated with this object
- gAgentAvatarp->stopMotionFromSource(mID);
- }
- }
-
- if (flagCameraSource())
- {
- LLFollowCamMgr::removeFollowCamParams(mID);
- }
-
- sNumZombieObjects++;
- }
-}
-
-void LLViewerObject::dump() const
-{
- llinfos << "Type: " << pCodeToString(mPrimitiveCode) << llendl;
- llinfos << "Drawable: " << (LLDrawable *)mDrawable << llendl;
- llinfos << "Update Age: " << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs << llendl;
-
- llinfos << "Parent: " << getParent() << llendl;
- llinfos << "ID: " << mID << llendl;
- llinfos << "LocalID: " << mLocalID << llendl;
- llinfos << "PositionRegion: " << getPositionRegion() << llendl;
- llinfos << "PositionAgent: " << getPositionAgent() << llendl;
- llinfos << "PositionGlobal: " << getPositionGlobal() << llendl;
- llinfos << "Velocity: " << getVelocity() << llendl;
- if (mDrawable.notNull() && mDrawable->getNumFaces())
- {
- LLFacePool *poolp = mDrawable->getFace(0)->getPool();
- if (poolp)
- {
- llinfos << "Pool: " << poolp << llendl;
- llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl;
- }
- }
- //llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl;
- //llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl;
- /*
- llinfos << "Velocity: " << getVelocity() << llendl;
- llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl;
- llinfos << "UsePhysics: " << usePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl;
- llinfos << "AppAngle: " << mAppAngle << llendl;
- llinfos << "PixelArea: " << mPixelArea << llendl;
-
- char buffer[1000];
- char *key;
- for (key = mNameValuePairs.getFirstKey(); key; key = mNameValuePairs.getNextKey() )
- {
- mNameValuePairs[key]->printNameValue(buffer);
- llinfos << buffer << llendl;
- }
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- llinfos << " child " << child->getID() << llendl;
- }
- */
-}
-
-void LLViewerObject::printNameValuePairs() const
-{
- for (name_value_map_t::const_iterator iter = mNameValuePairs.begin();
- iter != mNameValuePairs.end(); iter++)
- {
- LLNameValue* nv = iter->second;
- llinfos << nv->printNameValue() << llendl;
- }
-}
-
-void LLViewerObject::initVOClasses()
-{
- // Initialized shared class stuff first.
- LLVOAvatar::initClass();
- LLVOTree::initClass();
- llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl;
- LLVOGrass::initClass();
- LLVOWater::initClass();
- LLVOVolume::initClass();
-}
-
-void LLViewerObject::cleanupVOClasses()
-{
- LLVOGrass::cleanupClass();
- LLVOWater::cleanupClass();
- LLVOTree::cleanupClass();
- LLVOAvatar::cleanupClass();
- LLVOVolume::cleanupClass();
-}
-
-// Replaces all name value pairs with data from \n delimited list
-// Does not update server
-void LLViewerObject::setNameValueList(const std::string& name_value_list)
-{
- // Clear out the old
- for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ;
- mNameValuePairs.clear();
-
- // Bring in the new
- std::string::size_type length = name_value_list.length();
- std::string::size_type start = 0;
- while (start < length)
- {
- std::string::size_type end = name_value_list.find_first_of("\n", start);
- if (end == std::string::npos) end = length;
- if (end > start)
- {
- std::string tok = name_value_list.substr(start, end - start);
- addNVPair(tok);
- }
- start = end+1;
- }
-}
-
-
-// This method returns true if the object is over land owned by the
-// agent.
-bool LLViewerObject::isReturnable()
-{
- if (isAttachment())
- {
- return false;
- }
- std::vector<LLBBox> boxes;
- boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned());
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- boxes.push_back(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned());
- }
-
- return mRegionp
- && mRegionp->objectIsReturnable(getPositionRegion(), boxes);
-}
-
-BOOL LLViewerObject::setParent(LLViewerObject* parent)
-{
- if(mParent != parent)
- {
- LLViewerObject* old_parent = (LLViewerObject*)mParent ;
- BOOL ret = LLPrimitive::setParent(parent);
- if(ret && old_parent && parent)
- {
- old_parent->removeChild(this) ;
- }
- return ret ;
- }
-
- return FALSE ;
-}
-
-void LLViewerObject::addChild(LLViewerObject *childp)
-{
- for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i)
- {
- if (*i == childp)
- { //already has child
- return;
- }
- }
-
- if (!isAvatar())
- {
- // propagate selection properties
- childp->mbCanSelect = mbCanSelect;
- }
-
- if(childp->setParent(this))
- {
- mChildList.push_back(childp);
- }
-}
-
-void LLViewerObject::removeChild(LLViewerObject *childp)
-{
- for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i)
- {
- if (*i == childp)
- {
- if (!childp->isAvatar() && mDrawable.notNull() && mDrawable->isActive() && childp->mDrawable.notNull() && !isAvatar())
- {
- gPipeline.markRebuild(childp->mDrawable, LLDrawable::REBUILD_VOLUME);
- }
-
- mChildList.erase(i);
-
- if(childp->getParent() == this)
- {
- childp->setParent(NULL);
- }
- break;
- }
- }
-
- if (childp->isSelected())
- {
- LLSelectMgr::getInstance()->deselectObjectAndFamily(childp);
- BOOL add_to_end = TRUE;
- LLSelectMgr::getInstance()->selectObjectAndFamily(childp, add_to_end);
- }
-}
-
-void LLViewerObject::addThisAndAllChildren(std::vector<LLViewerObject*>& objects)
-{
- objects.push_back(this);
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- if (!child->isAvatar())
- {
- child->addThisAndAllChildren(objects);
- }
- }
-}
-
-void LLViewerObject::addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects)
-{
- objects.push_back(this);
- // don't add any attachments when temporarily selecting avatar
- if (isAvatar())
- {
- return;
- }
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- if ( (!child->isAvatar()) && (!child->isJointChild()))
- {
- child->addThisAndNonJointChildren(objects);
- }
- }
-}
-
-BOOL LLViewerObject::isChild(LLViewerObject *childp) const
-{
- for (child_list_t::const_iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* testchild = *iter;
- if (testchild == childp)
- return TRUE;
- }
- return FALSE;
-}
-
-
-// returns TRUE if at least one avatar is sitting on this object
-BOOL LLViewerObject::isSeat() const
-{
- for (child_list_t::const_iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- if (child->isAvatar())
- {
- return TRUE;
- }
- }
- return FALSE;
-
-}
-
-BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp)
-{
- if (mDrawable.isNull())
- {
- return FALSE;
- }
-
- BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL);
- if(!ret)
- {
- return FALSE ;
- }
- LLDrawable* old_parent = mDrawable->mParent;
- mDrawable->mParent = parentp;
-
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
- if( (old_parent != parentp && old_parent)
- || (parentp && parentp->isActive()))
- {
- // *TODO we should not be relying on setDrawable parent to call markMoved
- gPipeline.markMoved(mDrawable, FALSE);
- }
- else if (!mDrawable->isAvatar())
- {
- mDrawable->updateXform(TRUE);
- /*if (!mDrawable->getSpatialGroup())
- {
- mDrawable->movePartition();
- }*/
- }
-
- return ret;
-}
-
-// Show or hide particles, icon and HUD
-void LLViewerObject::hideExtraDisplayItems( BOOL hidden )
-{
- if( mPartSourcep.notNull() )
- {
- LLViewerPartSourceScript *partSourceScript = mPartSourcep.get();
- partSourceScript->setSuspended( hidden );
- }
-
- if( mText.notNull() )
- {
- LLHUDText *hudText = mText.get();
- hudText->setHidden( hidden );
- }
-
- if( mIcon.notNull() )
- {
- LLHUDIcon *hudIcon = mIcon.get();
- hudIcon->setHidden( hidden );
- }
-}
-
-U32 LLViewerObject::checkMediaURL(const std::string &media_url)
-{
- U32 retval = (U32)0x0;
- if (!mMedia && !media_url.empty())
- {
- retval |= MEDIA_URL_ADDED;
- mMedia = new LLViewerObjectMedia;
- mMedia->mMediaURL = media_url;
- mMedia->mMediaType = LLViewerObject::MEDIA_SET;
- mMedia->mPassedWhitelist = FALSE;
- }
- else if (mMedia)
- {
- if (media_url.empty())
- {
- retval |= MEDIA_URL_REMOVED;
- delete mMedia;
- mMedia = NULL;
- }
- else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test.
- {
- /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() &&
- LLTextureEntry::getVersionFromMediaVersionString(media_url) ==
- LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1))
- */
- {
- // If the media URL is different and WE were not the one who
- // changed it, mark dirty.
- retval |= MEDIA_URL_UPDATED;
- }
- mMedia->mMediaURL = media_url;
- mMedia->mPassedWhitelist = FALSE;
- }
- }
- return retval;
-}
-
-U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
- void **user_data,
- U32 block_num,
- const EObjectUpdateType update_type,
- LLDataPacker *dp)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
- U32 retval = 0x0;
-
- // Coordinates of objects on simulators are region-local.
- U64 region_handle;
- mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);
-
- {
- LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle);
- if(regionp != mRegionp && regionp && mRegionp)//region cross
- {
- //this is the redundant position and region update, but it is necessary in case the viewer misses the following
- //position and region update messages from sim.
- //this redundant update should not cause any problems.
- LLVector3 delta_pos = mRegionp->getOriginAgent() - regionp->getOriginAgent();
- setPositionParent(getPosition() + delta_pos); //update to the new region position immediately.
- setRegion(regionp) ; //change the region.
- }
- else
- {
- mRegionp = regionp ;
- }
- }
-
- if (!mRegionp)
- {
- U32 x, y;
- from_region_handle(region_handle, &x, &y);
-
- llerrs << "Object has invalid region " << x << ":" << y << "!" << llendl;
- return retval;
- }
-
- U16 time_dilation16;
- mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16);
- F32 time_dilation = ((F32) time_dilation16) / 65535.f;
- mTimeDilation = time_dilation;
- mRegionp->setTimeDilation(time_dilation);
-
- // this will be used to determine if we've really changed position
- // Use getPosition, not getPositionRegion, since this is what we're comparing directly against.
- LLVector3 test_pos_parent = getPosition();
-
- U8 data[60+16]; // This needs to match the largest size below.
-#ifdef LL_BIG_ENDIAN
- U16 valswizzle[4];
-#endif
- U16 *val;
- const F32 size = LLWorld::getInstance()->getRegionWidthInMeters();
- const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight();
- const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight();
- S32 length;
- S32 count;
- S32 this_update_precision = 32; // in bits
-
- // Temporaries, because we need to compare w/ previous to set dirty flags...
- LLVector3 new_pos_parent;
- LLVector3 new_vel;
- LLVector3 new_acc;
- LLVector3 new_angv;
- LLVector3 old_angv = getAngularVelocity();
- LLQuaternion new_rot;
- LLVector3 new_scale = getScale();
-
- U32 parent_id = 0;
- U8 material = 0;
- U8 click_action = 0;
- U32 crc = 0;
-
- bool old_special_hover_cursor = specialHoverCursor();
-
- LLViewerObject *cur_parentp = (LLViewerObject *)getParent();
-
- if (cur_parentp)
- {
- parent_id = cur_parentp->mLocalID;
- }
-
- if (!dp)
- {
- switch(update_type)
- {
- case OUT_FULL:
- {
-#ifdef DEBUG_UPDATE_TYPE
- llinfos << "Full:" << getID() << llendl;
-#endif
- //clear cost and linkset cost
- mCostStale = true;
- if (isSelected())
- {
- gFloaterTools->dirty();
- }
-
- LLUUID audio_uuid;
- LLUUID owner_id; // only valid if audio_uuid or particle system is not null
- F32 gain;
- U8 sound_flags;
-
- mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num);
- mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_ParentID, parent_id, block_num);
- mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound, audio_uuid, block_num );
- // HACK: Owner id only valid if non-null sound id or particle system
- mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num );
- mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num );
- mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num );
- mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num );
- mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num);
- mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num );
- length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData);
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num);
-
- mTotalCRC = crc;
-
- // Owner ID used for sound muting or particle system muting
- setAttachedSound(audio_uuid, owner_id, gain, sound_flags);
-
- U8 old_material = getMaterial();
- if (old_material != material)
- {
- setMaterial(material);
- if (mDrawable.notNull())
- {
- gPipeline.markMoved(mDrawable, FALSE); // undamped
- }
- }
- setClickAction(click_action);
-
- count = 0;
- LLVector4 collision_plane;
-
- switch(length)
- {
- case (60 + 16):
- // pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- count += sizeof(LLVector4);
- // fall through
- case 60:
- this_update_precision = 32;
- // this is a terse update
- // pos
- htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // vel
- htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // acc
- htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // theta
- {
- LLVector3 vec;
- htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- new_rot.unpackFromVector3(vec);
- }
- count += sizeof(LLVector3);
- // omega
- htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- if (new_angv.isExactlyZero())
- {
- // reset rotation time
- resetRot();
- }
- setAngularVelocity(new_angv);
-#if LL_DARWIN
- if (length == 76)
- {
- setAngularVelocity(LLVector3::zero);
- }
-#endif
- break;
- case(32 + 16):
- // pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- count += sizeof(LLVector4);
- // fall through
- case 32:
- this_update_precision = 16;
- test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
-
- // This is a terse 16 update, so treat data as an array of U16's.
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- count += sizeof(U16)*3;
- new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT);
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- count += sizeof(U16)*3;
- setVelocity(LLVector3(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size)));
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- count += sizeof(U16)*3;
- setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size)));
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- count += sizeof(U16)*4;
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f);
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- new_angv.setVec(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- if (new_angv.isExactlyZero())
- {
- // reset rotation time
- resetRot();
- }
- setAngularVelocity(new_angv);
- break;
-
- case 16:
- this_update_precision = 8;
- test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
- // this is a terse 8 update
- new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT);
-
- setVelocity(U8_to_F32(data[3], -size, size),
- U8_to_F32(data[4], -size, size),
- U8_to_F32(data[5], -size, size) );
-
- setAcceleration(U8_to_F32(data[6], -size, size),
- U8_to_F32(data[7], -size, size),
- U8_to_F32(data[8], -size, size) );
-
- new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f);
- new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f);
- new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f);
- new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f);
-
- new_angv.setVec(U8_to_F32(data[13], -size, size),
- U8_to_F32(data[14], -size, size),
- U8_to_F32(data[15], -size, size) );
- if (new_angv.isExactlyZero())
- {
- // reset rotation time
- resetRot();
- }
- setAngularVelocity(new_angv);
- break;
- }
-
- ////////////////////////////////////////////////////
- //
- // Here we handle data specific to the full message.
- //
-
- U32 flags;
- mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num);
- // clear all but local flags
- mFlags &= FLAGS_LOCAL;
- mFlags |= flags;
-
- U8 state;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
- mState = state;
-
- // ...new objects that should come in selected need to be added to the selected list
- mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
-
- // Set all name value pairs
- S32 nv_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_NameValue);
- if (nv_size > 0)
- {
- std::string name_value_list;
- mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_NameValue, name_value_list, block_num);
- setNameValueList(name_value_list);
- }
-
- // Clear out any existing generic data
- if (mData)
- {
- delete [] mData;
- }
-
- // Check for appended generic data
- S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Data);
- if (data_size <= 0)
- {
- mData = NULL;
- }
- else
- {
- // ...has generic data
- mData = new U8[data_size];
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, mData, data_size, block_num);
- }
-
- S32 text_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Text);
- if (text_size > 1)
- {
- // Setup object text
- if (!mText)
- {
- mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
- mText->setFont(LLFontGL::getFontSansSerif());
- mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
- mText->setMaxLines(-1);
- mText->setSourceObject(this);
- mText->setOnHUDAttachment(isHUDAttachment());
- }
-
- std::string temp_string;
- mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, temp_string, block_num );
-
- LLColor4U coloru;
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num);
-
- // alpha was flipped so that it zero encoded better
- coloru.mV[3] = 255 - coloru.mV[3];
- mText->setColor(LLColor4(coloru));
- mText->setString(temp_string);
-
- if (mDrawable.notNull())
- {
- setChanged(MOVED | SILHOUETTE);
- gPipeline.markMoved(mDrawable, FALSE); // undamped
- }
- }
- else if (mText.notNull())
- {
- mText->markDead();
- mText = NULL;
- }
-
- std::string media_url;
- mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num);
- retval |= checkMediaURL(media_url);
-
- //
- // Unpack particle system data
- //
- unpackParticleSource(block_num, owner_id);
-
- // Mark all extra parameters not used
- std::map<U16, ExtraParameter*>::iterator iter;
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- iter->second->in_use = FALSE;
- }
-
- // Unpack extra parameters
- S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ExtraParams);
- if (size > 0)
- {
- U8 *buffer = new U8[size];
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ExtraParams, buffer, size, block_num);
- LLDataPackerBinaryBuffer dp(buffer, size);
-
- U8 num_parameters;
- dp.unpackU8(num_parameters, "num_params");
- U8 param_block[MAX_OBJECT_PARAMS_SIZE];
- for (U8 param=0; param<num_parameters; ++param)
- {
- U16 param_type;
- S32 param_size;
- dp.unpackU16(param_type, "param_type");
- dp.unpackBinaryData(param_block, param_size, "param_data");
- //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl;
- LLDataPackerBinaryBuffer dp2(param_block, param_size);
- unpackParameterEntry(param_type, &dp2);
- }
- delete[] buffer;
- }
-
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- if (!iter->second->in_use)
- {
- // Send an update message in case it was formerly in use
- parameterChanged(iter->first, iter->second->data, FALSE, false);
- }
- }
-
- U8 joint_type = 0;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_JointType, joint_type, block_num);
- if (joint_type)
- {
- // create new joint info
- if (!mJointInfo)
- {
- mJointInfo = new LLVOJointInfo;
- }
- mJointInfo->mJointType = (EHavokJointType) joint_type;
- mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointPivot, mJointInfo->mPivot, block_num);
- mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointAxisOrAnchor, mJointInfo->mAxisOrAnchor, block_num);
- }
- else if (mJointInfo)
- {
- // this joint info is no longer needed
- delete mJointInfo;
- mJointInfo = NULL;
- }
-
- break;
- }
-
- case OUT_TERSE_IMPROVED:
- {
-#ifdef DEBUG_UPDATE_TYPE
- llinfos << "TI:" << getID() << llendl;
-#endif
- length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData);
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num);
- count = 0;
- LLVector4 collision_plane;
-
- switch(length)
- {
- case(60 + 16):
- // pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- count += sizeof(LLVector4);
- // fall through
- case 60:
- // this is a terse 32 update
- // pos
- this_update_precision = 32;
- htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // vel
- htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // acc
- htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // theta
- {
- LLVector3 vec;
- htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- new_rot.unpackFromVector3(vec);
- }
- count += sizeof(LLVector3);
- // omega
- htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- if (new_angv.isExactlyZero())
- {
- // reset rotation time
- resetRot();
- }
- setAngularVelocity(new_angv);
-#if LL_DARWIN
- if (length == 76)
- {
- setAngularVelocity(LLVector3::zero);
- }
-#endif
- break;
- case(32 + 16):
- // pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- count += sizeof(LLVector4);
- // fall through
- case 32:
- // this is a terse 16 update
- this_update_precision = 16;
- test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- count += sizeof(U16)*3;
- new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT);
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- count += sizeof(U16)*3;
- setVelocity(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- count += sizeof(U16)*3;
- setAcceleration(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- count += sizeof(U16)*4;
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f);
-
-#ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
-#else
- val = (U16 *) &data[count];
-#endif
- setAngularVelocity( U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- break;
-
- case 16:
- // this is a terse 8 update
- this_update_precision = 8;
- test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
- new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT);
-
- setVelocity(U8_to_F32(data[3], -size, size),
- U8_to_F32(data[4], -size, size),
- U8_to_F32(data[5], -size, size) );
-
- setAcceleration(U8_to_F32(data[6], -size, size),
- U8_to_F32(data[7], -size, size),
- U8_to_F32(data[8], -size, size) );
-
- new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f);
- new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f);
- new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f);
- new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f);
-
- setAngularVelocity( U8_to_F32(data[13], -size, size),
- U8_to_F32(data[14], -size, size),
- U8_to_F32(data[15], -size, size) );
- break;
- }
-
- U8 state;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
- mState = state;
- break;
- }
-
- default:
- break;
-
- }
- }
- else
- {
- // handle the compressed case
- LLUUID sound_uuid;
- LLUUID owner_id;
- F32 gain = 0;
- U8 sound_flags = 0;
- F32 cutoff = 0;
-
- U16 val[4];
-
- U8 state;
-
- dp->unpackU8(state, "State");
- mState = state;
-
- switch(update_type)
- {
- case OUT_TERSE_IMPROVED:
- {
-#ifdef DEBUG_UPDATE_TYPE
- llinfos << "CompTI:" << getID() << llendl;
-#endif
- U8 value;
- dp->unpackU8(value, "agent");
- if (value)
- {
- LLVector4 collision_plane;
- dp->unpackVector4(collision_plane, "Plane");
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- }
- test_pos_parent = getPosition();
- dp->unpackVector3(new_pos_parent, "Pos");
- dp->unpackU16(val[VX], "VelX");
- dp->unpackU16(val[VY], "VelY");
- dp->unpackU16(val[VZ], "VelZ");
- setVelocity(U16_to_F32(val[VX], -128.f, 128.f),
- U16_to_F32(val[VY], -128.f, 128.f),
- U16_to_F32(val[VZ], -128.f, 128.f));
- dp->unpackU16(val[VX], "AccX");
- dp->unpackU16(val[VY], "AccY");
- dp->unpackU16(val[VZ], "AccZ");
- setAcceleration(U16_to_F32(val[VX], -64.f, 64.f),
- U16_to_F32(val[VY], -64.f, 64.f),
- U16_to_F32(val[VZ], -64.f, 64.f));
-
- dp->unpackU16(val[VX], "ThetaX");
- dp->unpackU16(val[VY], "ThetaY");
- dp->unpackU16(val[VZ], "ThetaZ");
- dp->unpackU16(val[VS], "ThetaS");
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VS] = U16_to_F32(val[VS], -1.f, 1.f);
- dp->unpackU16(val[VX], "AccX");
- dp->unpackU16(val[VY], "AccY");
- dp->unpackU16(val[VZ], "AccZ");
- setAngularVelocity( U16_to_F32(val[VX], -64.f, 64.f),
- U16_to_F32(val[VY], -64.f, 64.f),
- U16_to_F32(val[VZ], -64.f, 64.f));
- }
- break;
- case OUT_FULL_COMPRESSED:
- case OUT_FULL_CACHED:
- {
-#ifdef DEBUG_UPDATE_TYPE
- llinfos << "CompFull:" << getID() << llendl;
-#endif
- mCostStale = true;
-
- if (isSelected())
- {
- gFloaterTools->dirty();
- }
-
- dp->unpackU32(crc, "CRC");
- mTotalCRC = crc;
- dp->unpackU8(material, "Material");
- U8 old_material = getMaterial();
- if (old_material != material)
- {
- setMaterial(material);
- if (mDrawable.notNull())
- {
- gPipeline.markMoved(mDrawable, FALSE); // undamped
- }
- }
- dp->unpackU8(click_action, "ClickAction");
- setClickAction(click_action);
- dp->unpackVector3(new_scale, "Scale");
- dp->unpackVector3(new_pos_parent, "Pos");
- LLVector3 vec;
- dp->unpackVector3(vec, "Rot");
- new_rot.unpackFromVector3(vec);
- setAcceleration(LLVector3::zero);
-
- U32 value;
- dp->unpackU32(value, "SpecialCode");
- dp->setPassFlags(value);
- dp->unpackUUID(owner_id, "Owner");
-
- if (value & 0x80)
- {
- dp->unpackVector3(vec, "Omega");
- setAngularVelocity(vec);
- }
-
- if (value & 0x20)
- {
- dp->unpackU32(parent_id, "ParentID");
- }
- else
- {
- parent_id = 0;
- }
-
- S32 sp_size;
- U32 size;
- if (value & 0x2)
- {
- sp_size = 1;
- delete [] mData;
- mData = new U8[1];
- dp->unpackU8(((U8*)mData)[0], "TreeData");
- }
- else if (value & 0x1)
- {
- dp->unpackU32(size, "ScratchPadSize");
- delete [] mData;
- mData = new U8[size];
- dp->unpackBinaryData((U8 *)mData, sp_size, "PartData");
- }
- else
- {
- mData = NULL;
- }
-
- // Setup object text
- if (!mText && (value & 0x4))
- {
- mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
- mText->setFont(LLFontGL::getFontSansSerif());
- mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
- mText->setMaxLines(-1); // Set to match current agni behavior.
- mText->setSourceObject(this);
- mText->setOnHUDAttachment(isHUDAttachment());
- }
-
- if (value & 0x4)
- {
- std::string temp_string;
- dp->unpackString(temp_string, "Text");
- LLColor4U coloru;
- dp->unpackBinaryDataFixed(coloru.mV, 4, "Color");
- coloru.mV[3] = 255 - coloru.mV[3];
- mText->setColor(LLColor4(coloru));
- mText->setString(temp_string);
-
- setChanged(TEXTURE);
- }
- else if(mText.notNull())
- {
- mText->markDead();
- mText = NULL;
- }
-
- std::string media_url;
- if (value & 0x200)
- {
- dp->unpackString(media_url, "MediaURL");
- }
- retval |= checkMediaURL(media_url);
-
- //
- // Unpack particle system data
- //
- if (value & 0x8)
- {
- unpackParticleSource(*dp, owner_id);
- }
- else
- {
- deleteParticleSource();
- }
-
- // Mark all extra parameters not used
- std::map<U16, ExtraParameter*>::iterator iter;
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- iter->second->in_use = FALSE;
- }
-
- // Unpack extra params
- U8 num_parameters;
- dp->unpackU8(num_parameters, "num_params");
- U8 param_block[MAX_OBJECT_PARAMS_SIZE];
- for (U8 param=0; param<num_parameters; ++param)
- {
- U16 param_type;
- S32 param_size;
- dp->unpackU16(param_type, "param_type");
- dp->unpackBinaryData(param_block, param_size, "param_data");
- //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl;
- LLDataPackerBinaryBuffer dp2(param_block, param_size);
- unpackParameterEntry(param_type, &dp2);
- }
-
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- if (!iter->second->in_use)
- {
- // Send an update message in case it was formerly in use
- parameterChanged(iter->first, iter->second->data, FALSE, false);
- }
- }
-
- if (value & 0x10)
- {
- dp->unpackUUID(sound_uuid, "SoundUUID");
- dp->unpackF32(gain, "SoundGain");
- dp->unpackU8(sound_flags, "SoundFlags");
- dp->unpackF32(cutoff, "SoundRadius");
- }
-
- if (value & 0x100)
- {
- std::string name_value_list;
- dp->unpackString(name_value_list, "NV");
-
- setNameValueList(name_value_list);
- }
-
- mTotalCRC = crc;
-
- setAttachedSound(sound_uuid, owner_id, gain, sound_flags);
-
- // only get these flags on updates from sim, not cached ones
- // Preload these five flags for every object.
- // Finer shades require the object to be selected, and the selection manager
- // stores the extended permission info.
- U32 flags;
- mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num);
- // keep local flags and overwrite remote-controlled flags
- mFlags = (mFlags & FLAGS_LOCAL) | flags;
-
- // ...new objects that should come in selected need to be added to the selected list
- mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
- }
- break;
-
- default:
- break;
- }
- }
-
- //
- // Fix object parenting.
- //
- BOOL b_changed_status = FALSE;
-
- if (OUT_TERSE_IMPROVED != update_type)
- {
- // We only need to update parenting on full updates, terse updates
- // don't send parenting information.
- if (!cur_parentp)
- {
- if (parent_id == 0)
- {
- // No parent now, no parent in message -> do nothing
- }
- else
- {
- // No parent now, new parent in message -> attach to that parent if possible
- LLUUID parent_uuid;
- LLViewerObjectList::getUUIDFromLocal(parent_uuid,
- parent_id,
- mesgsys->getSenderIP(),
- mesgsys->getSenderPort());
-
- LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid);
-
- //
- // Check to see if we have the corresponding viewer object for the parent.
- //
- if (sent_parentp && sent_parentp->getParent() == this)
- {
- // Try to recover if we attempt to attach a parent to its child
- llwarns << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << llendl;
- this->removeChild(sent_parentp);
- sent_parentp->setDrawableParent(NULL);
- }
-
- if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead())
- {
- //
- // We have a viewer object for the parent, and it's not dead.
- // Do the actual reparenting here.
- //
-
- // new parent is valid
- b_changed_status = TRUE;
- // ...no current parent, so don't try to remove child
- if (mDrawable.notNull())
- {
- if (mDrawable->isDead() || !mDrawable->getVObj())
- {
- llwarns << "Drawable is dead or no VObj!" << llendl;
- sent_parentp->addChild(this);
- }
- else
- {
- if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 1
- {
- // Bad, we got a cycle somehow.
- // Kill both the parent and the child, and
- // set cache misses for both of them.
- llwarns << "Attempting to recover from parenting cycle!" << llendl;
- llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl;
- llwarns << "Adding to cache miss list" << llendl;
- setParent(NULL);
- sent_parentp->setParent(NULL);
- getRegion()->addCacheMissFull(getLocalID());
- getRegion()->addCacheMissFull(sent_parentp->getLocalID());
- gObjectList.killObject(sent_parentp);
- gObjectList.killObject(this);
- return retval;
- }
- sent_parentp->addChild(this);
- // make sure this object gets a non-damped update
- if (sent_parentp->mDrawable.notNull())
- {
- gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped
- }
- }
- }
- else
- {
- sent_parentp->addChild(this);
- }
-
- // Show particles, icon and HUD
- hideExtraDisplayItems( FALSE );
-
- setChanged(MOVED | SILHOUETTE);
- }
- else
- {
- //
- // No corresponding viewer object for the parent, put the various
- // pieces on the orphan list.
- //
-
- //parent_id
- U32 ip = mesgsys->getSenderIP();
- U32 port = mesgsys->getSenderPort();
-
- gObjectList.orphanize(this, parent_id, ip, port);
-
- // Hide particles, icon and HUD
- hideExtraDisplayItems( TRUE );
- }
- }
- }
- else
- {
- // BUG: this is a bad assumption once border crossing is alowed
- if ( (parent_id == cur_parentp->mLocalID)
- &&(update_type == OUT_TERSE_IMPROVED))
- {
- // Parent now, same parent in message -> do nothing
-
- // Debugging for suspected problems with local ids.
- //LLUUID parent_uuid;
- //LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() );
- //if (parent_uuid != cur_parentp->getID() )
- //{
- // llerrs << "Local ID match but UUID mismatch of viewer object" << llendl;
- //}
- }
- else
- {
- // Parented now, different parent in message
- LLViewerObject *sent_parentp;
- if (parent_id == 0)
- {
- //
- // This object is no longer parented, we sent in a zero parent ID.
- //
- sent_parentp = NULL;
- }
- else
- {
- LLUUID parent_uuid;
- LLViewerObjectList::getUUIDFromLocal(parent_uuid,
- parent_id,
- gMessageSystem->getSenderIP(),
- gMessageSystem->getSenderPort());
- sent_parentp = gObjectList.findObject(parent_uuid);
-
- if (isAvatar())
- {
- // This logic is meant to handle the case where a sitting avatar has reached a new sim
- // ahead of the object she was sitting on (which is common as objects are transfered through
- // a slower route than agents)...
- // In this case, the local id for the object will not be valid, since the viewer has not received
- // a full update for the object from that sim yet, so we assume that the agent is still sitting
- // where she was originally. --RN
- if (!sent_parentp)
- {
- sent_parentp = cur_parentp;
- }
- }
- else if (!sent_parentp)
- {
- //
- // Switching parents, but we don't know the new parent.
- //
- U32 ip = mesgsys->getSenderIP();
- U32 port = mesgsys->getSenderPort();
-
- // We're an orphan, flag things appropriately.
- gObjectList.orphanize(this, parent_id, ip, port);
- }
- }
-
- // Reattach if possible.
- if (sent_parentp && sent_parentp != cur_parentp && sent_parentp != this)
- {
- // New parent is valid, detach and reattach
- b_changed_status = TRUE;
- if (mDrawable.notNull())
- {
- if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 2
- {
- // Bad, we got a cycle somehow.
- // Kill both the parent and the child, and
- // set cache misses for both of them.
- llwarns << "Attempting to recover from parenting cycle!" << llendl;
- llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl;
- llwarns << "Adding to cache miss list" << llendl;
- setParent(NULL);
- sent_parentp->setParent(NULL);
- getRegion()->addCacheMissFull(getLocalID());
- getRegion()->addCacheMissFull(sent_parentp->getLocalID());
- gObjectList.killObject(sent_parentp);
- gObjectList.killObject(this);
- return retval;
- }
- // make sure this object gets a non-damped update
- }
- cur_parentp->removeChild(this);
- sent_parentp->addChild(this);
- setChanged(MOVED | SILHOUETTE);
- sent_parentp->setChanged(MOVED | SILHOUETTE);
- if (sent_parentp->mDrawable.notNull())
- {
- gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped
- }
- }
- else if (!sent_parentp)
- {
- bool remove_parent = true;
- // No new parent, or the parent that we sent doesn't exist on the viewer.
- LLViewerObject *parentp = (LLViewerObject *)getParent();
- if (parentp)
- {
- if (parentp->getRegion() != getRegion())
- {
- // This is probably an object flying across a region boundary, the
- // object probably ISN'T being reparented, but just got an object
- // update out of order (child update before parent).
- //llinfos << "Don't reparent object handoffs!" << llendl;
- remove_parent = false;
- }
- }
-
- if (remove_parent)
- {
- b_changed_status = TRUE;
- if (mDrawable.notNull())
- {
- // clear parent to removeChild can put the drawable on the damped list
- setDrawableParent(NULL); // LLViewerObject::processUpdateMessage 3
- }
-
- cur_parentp->removeChild(this);
-
- if (mJointInfo && !parent_id)
- {
- // since this object is no longer parent-relative
- // we make sure we delete any joint info
- delete mJointInfo;
- mJointInfo = NULL;
- }
-
- setChanged(MOVED | SILHOUETTE);
-
- if (mDrawable.notNull())
- {
- // make sure this object gets a non-damped update
- gPipeline.markMoved(mDrawable, FALSE); // undamped
- }
- }
- }
- }
- }
- }
-
- new_rot.normQuat();
-
- if (sPingInterpolate)
- {
- LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender());
- if (cdp)
- {
- F32 ping_delay = 0.5f * mTimeDilation * ( ((F32)cdp->getPingDelay()) * 0.001f + gFrameDTClamped);
- LLVector3 diff = getVelocity() * ping_delay;
- new_pos_parent += diff;
- }
- else
- {
- llwarns << "findCircuit() returned NULL; skipping interpolation" << llendl;
- }
- }
-
- //////////////////////////
- //
- // Set the generic change flags...
- //
- //
-
- // WTF? If we're going to skip this message, why are we
- // doing all the parenting, etc above?
- U32 packet_id = mesgsys->getCurrentRecvPacketID();
- if (packet_id < mLatestRecvPacketID &&
- mLatestRecvPacketID - packet_id < 65536)
- {
- //skip application of this message, it's old
- return retval;
- }
-
- mLatestRecvPacketID = packet_id;
-
- // Set the change flags for scale
- if (new_scale != getScale())
- {
- setChanged(SCALED | SILHOUETTE);
- setScale(new_scale); // Must follow setting permYouOwner()
- }
-
- // first, let's see if the new position is actually a change
-
- //static S32 counter = 0;
-
- F32 vel_mag_sq = getVelocity().magVecSquared();
- F32 accel_mag_sq = getAcceleration().magVecSquared();
-
- if ( ((b_changed_status)||(test_pos_parent != new_pos_parent))
- ||( (!isSelected())
- &&( (vel_mag_sq != 0.f)
- ||(accel_mag_sq != 0.f)
- ||(this_update_precision > mBestUpdatePrecision))))
- {
- mBestUpdatePrecision = this_update_precision;
-
- LLVector3 diff = new_pos_parent - test_pos_parent ;
- F32 mag_sqr = diff.magVecSquared() ;
- if(llfinite(mag_sqr))
- {
- setPositionParent(new_pos_parent);
- }
- else
- {
- llwarns << "Can not move the object/avatar to an infinite location!" << llendl ;
-
- retval |= INVALID_UPDATE ;
- }
-
- if (mParent && ((LLViewerObject*)mParent)->isAvatar())
- {
- // we have changed the position of an attachment, so we need to clamp it
- LLVOAvatar *avatar = (LLVOAvatar*)mParent;
-
- avatar->clampAttachmentPositions();
- }
-
- // If we're snapping the position by more than 0.5m, update LLViewerStats::mAgentPositionSnaps
- if ( asAvatar() && asAvatar()->isSelf() && (mag_sqr > 0.25f) )
- {
- LLViewerStats::getInstance()->mAgentPositionSnaps.push( diff.length() );
- }
- }
-
- if (new_rot != mLastRot
- || new_angv != old_angv)
- {
- if (new_rot != mLastRot)
- {
- mLastRot = new_rot;
- setRotation(new_rot);
- }
-
- setChanged(ROTATED | SILHOUETTE);
-
- resetRot();
- }
-
-
- if ( gShowObjectUpdates )
- {
- if (!((mPrimitiveCode == LL_PCODE_LEGACY_AVATAR) && (((LLVOAvatar *) this)->isSelf()))
- && mRegionp)
- {
- LLViewerObject* object = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, mRegionp);
- LLVOTextBubble* bubble = (LLVOTextBubble*) object;
-
- if (update_type == OUT_TERSE_IMPROVED)
- {
- bubble->mColor.setVec(0.f, 0.f, 1.f, 1.f);
- }
- else
- {
- bubble->mColor.setVec(1.f, 0.f, 0.f, 1.f);
- }
- object->setPositionGlobal(getPositionGlobal());
- gPipeline.addObject(object);
- }
- }
-
- if ((0.0f == vel_mag_sq) &&
- (0.0f == accel_mag_sq) &&
- (0.0f == getAngularVelocity().magVecSquared()))
- {
- mStatic = TRUE; // This object doesn't move!
- }
- else
- {
- mStatic = FALSE;
- }
-
-// BUG: This code leads to problems during group rotate and any scale operation.
-// Small discepencies between the simulator and viewer representations cause the
-// selection center to creep, leading to objects moving around the wrong center.
-//
-// Removing this, however, means that if someone else drags an object you have
-// selected, your selection center and dialog boxes will be wrong. It also means
-// that higher precision information on selected objects will be ignored.
-//
-// I believe the group rotation problem is fixed. JNC 1.21.2002
-//
- // Additionally, if any child is selected, need to update the dialogs and selection
- // center.
- BOOL needs_refresh = mUserSelected;
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- needs_refresh = needs_refresh || child->mUserSelected;
- }
-
- if (needs_refresh)
- {
- LLSelectMgr::getInstance()->updateSelectionCenter();
- dialog_refresh_all();
- }
-
-
- // Mark update time as approx. now, with the ping delay.
- // Ping delay is off because it's not set for velocity interpolation, causing
- // much jumping and hopping around...
-
-// U32 ping_delay = mesgsys->mCircuitInfo.getPingDelay();
- mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds();
- mLastMessageUpdateSecs = mLastInterpUpdateSecs;
- if (mDrawable.notNull())
- {
- // Don't clear invisibility flag on update if still orphaned!
- if (mDrawable->isState(LLDrawable::FORCE_INVISIBLE) && !mOrphaned)
- {
-// lldebugs << "Clearing force invisible: " << mID << ":" << getPCodeString() << ":" << getPositionAgent() << llendl;
- mDrawable->setState(LLDrawable::CLEAR_INVISIBLE);
- }
- }
-
- // Update special hover cursor status
- bool special_hover_cursor = specialHoverCursor();
- if (old_special_hover_cursor != special_hover_cursor
- && mDrawable.notNull())
- {
- mDrawable->updateSpecialHoverCursor(special_hover_cursor);
- }
-
- return retval;
-}
-
-BOOL LLViewerObject::isActive() const
-{
- return TRUE;
-}
-
-
-
-BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
-{
- static LLFastTimer::DeclareTimer ftm("Viewer Object");
- LLFastTimer t(ftm);
-
- if (mDead)
- {
- // It's dead. Don't update it.
- return TRUE;
- }
-
- // CRO - don't velocity interp linked objects!
- // Leviathan - but DO velocity interp joints
- if (!mStatic && sVelocityInterpolate && !isSelected())
- {
- // calculate dt from last update
- F32 dt_raw = (F32)(time - mLastInterpUpdateSecs);
- F32 dt = mTimeDilation * dt_raw;
-
- if (!mJointInfo)
- {
- applyAngularVelocity(dt);
- }
-
- LLViewerObject *parentp = (LLViewerObject *) getParent();
- if (mJointInfo)
- {
- if (parentp)
- {
- // do parent-relative stuff
- LLVector3 ang_vel = getAngularVelocity();
- F32 omega = ang_vel.magVecSquared();
- F32 angle = 0.0f;
- LLQuaternion dQ;
- if (omega > 0.00001f)
- {
- omega = sqrt(omega);
- angle = omega * dt;
- dQ.setQuat(angle, ang_vel);
- }
- LLVector3 pos = getPosition();
-
- if (HJT_HINGE == mJointInfo->mJointType)
- {
- // hinge = uniform circular motion
- LLVector3 parent_pivot = getVelocity();
- LLVector3 parent_axis = getAcceleration();
-
- angle = dt * (ang_vel * mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis
- dQ.setQuat(angle, mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis
- LLVector3 pivot_offset = pos - mJointInfo->mPivot; // pos in pivot-frame
- pivot_offset = pivot_offset * dQ; // new rotated pivot-frame pos
- pos = mJointInfo->mPivot + pivot_offset; // parent-frame
- LLViewerObject::setPosition(pos);
- LLQuaternion Q_PC = getRotation();
- setRotation(Q_PC * dQ);
- mLastInterpUpdateSecs = time;
- }
- else if (HJT_POINT == mJointInfo->mJointType)
- // || HJT_LPOINT == mJointInfo->mJointType)
- {
- // point-to-point = spin about axis and uniform circular motion
- // of axis about the pivot point
- //
- // NOTE: this interpolation scheme is not quite good enough to
- // reduce the bandwidth -- needs a gravitational correction.
- // Similarly for hinges with axes that deviate from vertical.
-
- LLQuaternion Q_PC = getRotation();
- Q_PC = Q_PC * dQ;
- setRotation(Q_PC);
-
- LLVector3 pivot_to_child = - mJointInfo->mAxisOrAnchor; // AxisOrAnchor = anchor
- pos = mJointInfo->mPivot + pivot_to_child * Q_PC;
- LLViewerObject::setPosition(pos);
- mLastInterpUpdateSecs = time;
- }
- /* else if (HJT_WHEEL == mJointInfo->mJointInfo)
- {
- // wheel = uniform rotation about axis, with linear
- // velocity interpolation (if any)
- LLVector3 parent_axis = getAcceleration(); // HACK -- accel stores the parent-axis (parent-frame)
-
- LLQuaternion Q_PC = getRotation();
-
- angle = dt * (parent_axis * ang_vel);
- dQ.setQuat(angle, parent_axis);
-
- Q_PC = Q_PC * dQ;
- setRotation(Q_PC);
-
- pos = getPosition() + dt * getVelocity();
- LLViewerObject::setPosition(pos);
- mLastInterpUpdateSecs = time;
- }*/
- }
- }
- else if (isAttachment())
- {
- mLastInterpUpdateSecs = time;
- return TRUE;
- }
- else
- { // Move object based on it's velocity and rotation
- interpolateLinearMotion(time, dt);
- }
- }
-
- updateDrawable(FALSE);
-
- return TRUE;
-}
-
-
-// Move an object due to idle-time viewer side updates by iterpolating motion
-void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt)
-{
- // linear motion
- // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object
- // updates represents the average velocity of the last timestep, rather than the final velocity.
- // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically
- //
- // *TODO: should also wrap linear accel/velocity in check
- // to see if object is selected, instead of explicitly
- // zeroing it out
-
- F64 time_since_last_update = time - mLastMessageUpdateSecs;
- if (time_since_last_update <= 0.0 || dt <= 0.f)
- {
- return;
- }
-
- LLVector3 accel = getAcceleration();
- LLVector3 vel = getVelocity();
-
- if (sMaxUpdateInterpolationTime <= 0.0)
- { // Old code path ... unbounded, simple interpolation
- if (!(accel.isExactlyZero() && vel.isExactlyZero()))
- {
- LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt;
-
- // region local
- setPositionRegion(pos + getPositionRegion());
- setVelocity(vel + accel*dt);
-
- // for objects that are spinning but not translating, make sure to flag them as having moved
- setChanged(MOVED | SILHOUETTE);
- }
- }
- else if (!accel.isExactlyZero() || !vel.isExactlyZero()) // object is moving
- { // Object is moving, and hasn't been too long since we got an update from the server
-
- // Calculate predicted position and velocity
- LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt;
- LLVector3 new_v = accel * dt;
-
- if (time_since_last_update > sPhaseOutUpdateInterpolationTime &&
- sPhaseOutUpdateInterpolationTime > 0.0)
- { // Haven't seen a viewer update in a while, check to see if the ciruit is still active
- if (mRegionp)
- { // The simulator will NOT send updates if the object continues normally on the path
- // predicted by the velocity and the acceleration (often gravity) sent to the viewer
- // So check to see if the circuit is blocked, which means the sim is likely in a long lag
- LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit( mRegionp->getHost() );
- if (cdp)
- {
- // Find out how many seconds since last packet arrived on the circuit
- F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime();
-
- if (!cdp->isAlive() || // Circuit is dead or blocked
- cdp->isBlocked() || // or doesn't seem to be getting any packets
- (time_since_last_packet > sPhaseOutUpdateInterpolationTime))
- {
- // Start to reduce motion interpolation since we haven't seen a server update in a while
- F64 time_since_last_interpolation = time - mLastInterpUpdateSecs;
- F64 phase_out = 1.0;
- if (time_since_last_update > sMaxUpdateInterpolationTime)
- { // Past the time limit, so stop the object
- phase_out = 0.0;
- //llinfos << "Motion phase out to zero" << llendl;
-
- // Kill angular motion as well. Note - not adding this due to paranoia
- // about stopping rotation for llTargetOmega objects and not having it restart
- // setAngularVelocity(LLVector3::zero);
- }
- else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs > sPhaseOutUpdateInterpolationTime)
- { // Last update was already phased out a bit
- phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) /
- (sMaxUpdateInterpolationTime - time_since_last_interpolation);
- //llinfos << "Continuing motion phase out of " << (F32) phase_out << llendl;
- }
- else
- { // Phase out from full value
- phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) /
- (sMaxUpdateInterpolationTime - sPhaseOutUpdateInterpolationTime);
- //llinfos << "Starting motion phase out of " << (F32) phase_out << llendl;
- }
- phase_out = llclamp(phase_out, 0.0, 1.0);
-
- new_pos = new_pos * ((F32) phase_out);
- new_v = new_v * ((F32) phase_out);
- }
- }
- }
- }
-
- new_pos = new_pos + getPositionRegion();
- new_v = new_v + vel;
-
-
- // Clamp interpolated position to minimum underground and maximum region height
- LLVector3d new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos);
- F32 min_height;
- if (isAvatar())
- { // Make a better guess about AVs not going underground
- min_height = LLWorld::getInstance()->resolveLandHeightGlobal(new_pos_global);
- min_height += (0.5f * getScale().mV[VZ]);
- }
- else
- { // This will put the object underground, but we can't tell if it will stop
- // at ground level or not
- min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global);
- }
-
- new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]);
- new_pos.mV[VZ] = llmin(LLWorld::getInstance()->getRegionMaxHeight(), new_pos.mV[VZ]);
-
- // Check to see if it's going off the region
- LLVector3 temp(new_pos);
- if (temp.clamp(0.f, mRegionp->getWidth()))
- { // Going off this region, so see if we might end up on another region
- LLVector3d old_pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion());
- new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos); // Re-fetch in case it got clipped above
-
- // Clip the positions to known regions
- LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global);
- if (clip_pos_global != new_pos_global)
- { // Was clipped, so this means we hit a edge where there is no region to enter
-
- //llinfos << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global)
- // << " from " << new_pos << llendl;
- new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global);
-
- // Stop motion and get server update for bouncing on the edge
- new_v.clear();
- setAcceleration(LLVector3::zero);
- }
- else
- { // Let predicted movement cross into another region
- //llinfos << "Predicting region crossing to " << new_pos << llendl;
- }
- }
-
- // Set new position and velocity
- setPositionRegion(new_pos);
- setVelocity(new_v);
-
- // for objects that are spinning but not translating, make sure to flag them as having moved
- setChanged(MOVED | SILHOUETTE);
- }
-
- // Update the last time we did anything
- mLastInterpUpdateSecs = time;
-}
-
-
-
-BOOL LLViewerObject::setData(const U8 *datap, const U32 data_size)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- delete [] mData;
-
- if (datap)
- {
- mData = new U8[data_size];
- if (!mData)
- {
- return FALSE;
- }
- memcpy(mData, datap, data_size); /* Flawfinder: ignore */
- }
- return TRUE;
-}
-
-// delete an item in the inventory, but don't tell the server. This is
-// used internally by remove, update, and savescript.
-// This will only delete the first item with an item_id in the list
-void LLViewerObject::deleteInventoryItem(const LLUUID& item_id)
-{
- if(mInventory)
- {
- LLInventoryObject::object_list_t::iterator it = mInventory->begin();
- LLInventoryObject::object_list_t::iterator end = mInventory->end();
- for( ; it != end; ++it )
- {
- if((*it)->getUUID() == item_id)
- {
- // This is safe only because we return immediatly.
- mInventory->erase(it); // will deref and delete it
- return;
- }
- }
- doInventoryCallback();
- }
-}
-
-void LLViewerObject::doUpdateInventory(
- LLPointer<LLViewerInventoryItem>& item,
- U8 key,
- bool is_new)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- LLViewerInventoryItem* old_item = NULL;
- if(TASK_INVENTORY_ITEM_KEY == key)
- {
- old_item = (LLViewerInventoryItem*)getInventoryObject(item->getUUID());
- }
- else if(TASK_INVENTORY_ASSET_KEY == key)
- {
- old_item = getInventoryItemByAsset(item->getAssetUUID());
- }
- LLUUID item_id;
- LLUUID new_owner;
- LLUUID new_group;
- BOOL group_owned = FALSE;
- if(old_item)
- {
- item_id = old_item->getUUID();
- new_owner = old_item->getPermissions().getOwner();
- new_group = old_item->getPermissions().getGroup();
- group_owned = old_item->getPermissions().isGroupOwned();
- old_item = NULL;
- }
- else
- {
- item_id = item->getUUID();
- }
- if(!is_new && mInventory)
- {
- // Attempt to update the local inventory. If we can get the
- // object perm, we have perfect visibility, so we want the
- // serial number to match. Otherwise, take our best guess and
- // make sure that the serial number does not match.
- deleteInventoryItem(item_id);
- LLPermissions perm(item->getPermissions());
- LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this);
- bool is_atomic = ((S32)LLAssetType::AT_OBJECT == item->getType()) ? false : true;
- if(obj_perm)
- {
- perm.setOwnerAndGroup(LLUUID::null, obj_perm->getOwner(), obj_perm->getGroup(), is_atomic);
- }
- else
- {
- if(group_owned)
- {
- perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic);
- }
- else if(!new_owner.isNull())
- {
- // The object used to be in inventory, so we can
- // assume the owner and group will match what they are
- // there.
- perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic);
- }
- // *FIX: can make an even better guess by using the mPermGroup flags
- else if(permYouOwner())
- {
- // best guess.
- perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic);
- --mInventorySerialNum;
- }
- else
- {
- // dummy it up.
- perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic);
- --mInventorySerialNum;
- }
- }
- LLViewerInventoryItem* oldItem = item;
- LLViewerInventoryItem* new_item = new LLViewerInventoryItem(oldItem);
- new_item->setPermissions(perm);
- mInventory->push_front(new_item);
- doInventoryCallback();
- ++mInventorySerialNum;
- }
-}
-
-// save a script, which involves removing the old one, and rezzing
-// in the new one. This method should be called with the asset id
-// of the new and old script AFTER the bytecode has been saved.
-void LLViewerObject::saveScript(
- const LLViewerInventoryItem* item,
- BOOL active,
- bool is_new)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- /*
- * XXXPAM Investigate not making this copy. Seems unecessary, but I'm unsure about the
- * interaction with doUpdateInventory() called below.
- */
- lldebugs << "LLViewerObject::saveScript() " << item->getUUID() << " " << item->getAssetUUID() << llendl;
- LLPointer<LLViewerInventoryItem> task_item =
- new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(),
- item->getAssetUUID(), item->getType(),
- item->getInventoryType(),
- item->getName(), item->getDescription(),
- item->getSaleInfo(), item->getFlags(),
- item->getCreationDate());
- task_item->setTransactionID(item->getTransactionID());
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RezScript);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
- msg->nextBlockFast(_PREHASH_UpdateBlock);
- msg->addU32Fast(_PREHASH_ObjectLocalID, (mLocalID));
- U8 enabled = active;
- msg->addBOOLFast(_PREHASH_Enabled, enabled);
- msg->nextBlockFast(_PREHASH_InventoryBlock);
- task_item->packMessage(msg);
- msg->sendReliable(mRegionp->getHost());
-
- // do the internal logic
- doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, is_new);
-}
-
-void LLViewerObject::moveInventory(const LLUUID& folder_id,
- const LLUUID& item_id)
-{
- lldebugs << "LLViewerObject::moveInventory " << item_id << llendl;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_MoveTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_FolderID, folder_id);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- msg->sendReliable(mRegionp->getHost());
-
- LLInventoryObject* inv_obj = getInventoryObject(item_id);
- if(inv_obj)
- {
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_obj;
- if(!item->getPermissions().allowCopyBy(gAgent.getID()))
- {
- deleteInventoryItem(item_id);
- ++mInventorySerialNum;
- }
- }
-}
-
-void LLViewerObject::dirtyInventory()
-{
- // If there aren't any LLVOInventoryListeners, we won't be
- // able to update our mInventory when it comes back from the
- // simulator, so we should not clear the inventory either.
- if(mInventory && !mInventoryCallbacks.empty())
- {
- mInventory->clear(); // will deref and delete entries
- delete mInventory;
- mInventory = NULL;
- mInventoryDirty = TRUE;
- }
-}
-
-void LLViewerObject::registerInventoryListener(LLVOInventoryListener* listener, void* user_data)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- LLInventoryCallbackInfo* info = new LLInventoryCallbackInfo;
- info->mListener = listener;
- info->mInventoryData = user_data;
- mInventoryCallbacks.push_front(info);
-}
-
-void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener)
-{
- if (listener == NULL)
- return;
- for (callback_list_t::iterator iter = mInventoryCallbacks.begin();
- iter != mInventoryCallbacks.end(); )
- {
- callback_list_t::iterator curiter = iter++;
- LLInventoryCallbackInfo* info = *curiter;
- if (info->mListener == listener)
- {
- delete info;
- mInventoryCallbacks.erase(curiter);
- break;
- }
- }
-}
-
-void LLViewerObject::clearInventoryListeners()
-{
- for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer());
- mInventoryCallbacks.clear();
-}
-
-void LLViewerObject::requestInventory()
-{
- mInventoryDirty = FALSE;
- if(mInventory)
- {
- //mInventory->clear() // will deref and delete it
- //delete mInventory;
- //mInventory = NULL;
- doInventoryCallback();
- }
- // throw away duplicate requests
- else
- {
- fetchInventoryFromServer();
- }
-}
-
-void LLViewerObject::fetchInventoryFromServer()
-{
- if (!mInventoryPending)
- {
- delete mInventory;
- mInventory = NULL;
- mInventoryDirty = FALSE;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RequestTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->sendReliable(mRegionp->getHost());
-
- // this will get reset by dirtyInventory or doInventoryCallback
- mInventoryPending = TRUE;
- }
-}
-
-struct LLFilenameAndTask
-{
- LLUUID mTaskID;
- std::string mFilename;
-#ifdef _DEBUG
- static S32 sCount;
- LLFilenameAndTask()
- {
- ++sCount;
- lldebugs << "Constructing LLFilenameAndTask: " << sCount << llendl;
- }
- ~LLFilenameAndTask()
- {
- --sCount;
- lldebugs << "Destroying LLFilenameAndTask: " << sCount << llendl;
- }
-private:
- LLFilenameAndTask(const LLFilenameAndTask& rhs);
- const LLFilenameAndTask& operator=(const LLFilenameAndTask& rhs) const;
-#endif
-};
-
-#ifdef _DEBUG
-S32 LLFilenameAndTask::sCount = 0;
-#endif
-
-// static
-void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- LLUUID task_id;
- msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id);
- LLViewerObject* object = gObjectList.findObject(task_id);
- if(!object)
- {
- llwarns << "LLViewerObject::processTaskInv object "
- << task_id << " does not exist." << llendl;
- return;
- }
-
- msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);
- LLFilenameAndTask* ft = new LLFilenameAndTask;
- ft->mTaskID = task_id;
-
- std::string unclean_filename;
- msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);
- ft->mFilename = LLDir::getScrubbedFileName(unclean_filename);
-
- if(ft->mFilename.empty())
- {
- lldebugs << "Task has no inventory" << llendl;
- // mock up some inventory to make a drop target.
- if(object->mInventory)
- {
- object->mInventory->clear(); // will deref and delete it
- }
- else
- {
- object->mInventory = new LLInventoryObject::object_list_t();
- }
- LLPointer<LLInventoryObject> obj;
- obj = new LLInventoryObject(object->mID, LLUUID::null,
- LLAssetType::AT_CATEGORY,
- LLTrans::getString("ViewerObjectContents").c_str());
- object->mInventory->push_front(obj);
- object->doInventoryCallback();
- delete ft;
- return;
- }
- gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename),
- ft->mFilename, LL_PATH_CACHE,
- object->mRegionp->getHost(),
- TRUE,
- &LLViewerObject::processTaskInvFile,
- (void**)ft,
- LLXferManager::HIGH_PRIORITY);
-}
-
-void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status)
-{
- LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data;
- LLViewerObject* object = NULL;
- if(ft && (0 == error_code) &&
- (object = gObjectList.findObject(ft->mTaskID)))
- {
- object->loadTaskInvFile(ft->mFilename);
- }
- else
- {
- // This Occurs When to requests were made, and the first one
- // has already handled it.
- lldebugs << "Problem loading task inventory. Return code: "
- << error_code << llendl;
- }
- delete ft;
-}
-
-void LLViewerObject::loadTaskInvFile(const std::string& filename)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename);
- llifstream ifs(filename_and_local_path);
- if(ifs.good())
- {
- char buffer[MAX_STRING]; /* Flawfinder: ignore */
- // *NOTE: This buffer size is hard coded into scanf() below.
- char keyword[MAX_STRING]; /* Flawfinder: ignore */
- if(mInventory)
- {
- mInventory->clear(); // will deref and delete it
- }
- else
- {
- mInventory = new LLInventoryObject::object_list_t;
- }
- while(ifs.good())
- {
- ifs.getline(buffer, MAX_STRING);
- sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */
- if(0 == strcmp("inv_item", keyword))
- {
- LLPointer<LLInventoryObject> inv = new LLViewerInventoryItem;
- inv->importLegacyStream(ifs);
- mInventory->push_front(inv);
- }
- else if(0 == strcmp("inv_object", keyword))
- {
- LLPointer<LLInventoryObject> inv = new LLInventoryObject;
- inv->importLegacyStream(ifs);
- inv->rename(LLTrans::getString("ViewerObjectContents").c_str());
- mInventory->push_front(inv);
- }
- else
- {
- llwarns << "Unknown token in inventory file '"
- << keyword << "'" << llendl;
- }
- }
- ifs.close();
- LLFile::remove(filename_and_local_path);
- }
- else
- {
- llwarns << "unable to load task inventory: " << filename_and_local_path
- << llendl;
- }
- doInventoryCallback();
-}
-
-void LLViewerObject::doInventoryCallback()
-{
- for (callback_list_t::iterator iter = mInventoryCallbacks.begin();
- iter != mInventoryCallbacks.end(); )
- {
- callback_list_t::iterator curiter = iter++;
- LLInventoryCallbackInfo* info = *curiter;
- if (info->mListener != NULL)
- {
- info->mListener->inventoryChanged(this,
- mInventory,
- mInventorySerialNum,
- info->mInventoryData);
- }
- else
- {
- llinfos << "LLViewerObject::doInventoryCallback() deleting bad listener entry." << llendl;
- delete info;
- mInventoryCallbacks.erase(curiter);
- }
- }
- mInventoryPending = FALSE;
-}
-
-void LLViewerObject::removeInventory(const LLUUID& item_id)
-{
- // close any associated floater properties
- LLFloaterReg::hideInstance("properties", item_id);
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RemoveTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- msg->sendReliable(mRegionp->getHost());
- deleteInventoryItem(item_id);
- ++mInventorySerialNum;
-}
-
-void LLViewerObject::updateInventory(
- LLViewerInventoryItem* item,
- U8 key,
- bool is_new)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- // This slices the object into what we're concerned about on the
- // viewer. The simulator will take the permissions and transfer
- // ownership.
- LLPointer<LLViewerInventoryItem> task_item =
- new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(),
- item->getAssetUUID(), item->getType(),
- item->getInventoryType(),
- item->getName(), item->getDescription(),
- item->getSaleInfo(),
- item->getFlags(),
- item->getCreationDate());
- task_item->setTransactionID(item->getTransactionID());
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_UpdateTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_UpdateData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->addU8Fast(_PREHASH_Key, key);
- msg->nextBlockFast(_PREHASH_InventoryData);
- task_item->packMessage(msg);
- msg->sendReliable(mRegionp->getHost());
-
- // do the internal logic
- doUpdateInventory(task_item, key, is_new);
-}
-
-void LLViewerObject::updateInventoryLocal(LLInventoryItem* item, U8 key)
-{
- LLPointer<LLViewerInventoryItem> task_item =
- new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(),
- item->getAssetUUID(), item->getType(),
- item->getInventoryType(),
- item->getName(), item->getDescription(),
- item->getSaleInfo(), item->getFlags(),
- item->getCreationDate());
-
- // do the internal logic
- const bool is_new = false;
- doUpdateInventory(task_item, key, is_new);
-}
-
-LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id)
-{
- LLInventoryObject* rv = NULL;
- if(mInventory)
- {
- LLInventoryObject::object_list_t::iterator it = mInventory->begin();
- LLInventoryObject::object_list_t::iterator end = mInventory->end();
- for ( ; it != end; ++it)
- {
- if((*it)->getUUID() == item_id)
- {
- rv = *it;
- break;
- }
- }
- }
- return rv;
-}
-
-void LLViewerObject::getInventoryContents(LLInventoryObject::object_list_t& objects)
-{
- if(mInventory)
- {
- LLInventoryObject::object_list_t::iterator it = mInventory->begin();
- LLInventoryObject::object_list_t::iterator end = mInventory->end();
- for( ; it != end; ++it)
- {
- if ((*it)->getType() != LLAssetType::AT_CATEGORY)
- {
- objects.push_back(*it);
- }
- }
- }
-}
-
-LLInventoryObject* LLViewerObject::getInventoryRoot()
-{
- if (!mInventory || !mInventory->size())
- {
- return NULL;
- }
- return mInventory->back();
-}
-
-LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& asset_id)
-{
- if (mInventoryDirty)
- llwarns << "Peforming inventory lookup for object " << mID << " that has dirty inventory!" << llendl;
-
- LLViewerInventoryItem* rv = NULL;
- if(mInventory)
- {
- LLViewerInventoryItem* item = NULL;
-
- LLInventoryObject::object_list_t::iterator it = mInventory->begin();
- LLInventoryObject::object_list_t::iterator end = mInventory->end();
- for( ; it != end; ++it)
- {
- LLInventoryObject* obj = *it;
- if(obj->getType() != LLAssetType::AT_CATEGORY)
- {
- // *FIX: gank-ass down cast!
- item = (LLViewerInventoryItem*)obj;
- if(item->getAssetUUID() == asset_id)
- {
- rv = item;
- break;
- }
- }
- }
- }
- return rv;
-}
-
-void LLViewerObject::updateViewerInventoryAsset(
- const LLViewerInventoryItem* item,
- const LLUUID& new_asset)
-{
- LLPointer<LLViewerInventoryItem> task_item =
- new LLViewerInventoryItem(item);
- task_item->setAssetUUID(new_asset);
-
- // do the internal logic
- doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, false);
-}
-
-void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent)
-{
- if (getVolume())
- { //volumes calculate pixel area and angle per face
- return;
- }
-
- LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent();
- LLVector3 pos_agent = getRenderPosition();
-
- F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX];
- F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY];
- F32 dz = viewer_pos_agent.mV[VZ] - pos_agent.mV[VZ];
-
- F32 max_scale = getMaxScale();
- F32 mid_scale = getMidScale();
- F32 min_scale = getMinScale();
-
- // IW: estimate - when close to large objects, computing range based on distance from center is no good
- // to try to get a min distance from face, subtract min_scale/2 from the range.
- // This means we'll load too much detail sometimes, but that's better than not enough
- // I don't think there's a better way to do this without calculating distance per-poly
- F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2;
-
- LLViewerCamera* camera = LLViewerCamera::getInstance();
- if (range < 0.001f || isHUDAttachment()) // range == zero
- {
- mAppAngle = 180.f;
- mPixelArea = (F32)camera->getScreenPixelArea();
- }
- else
- {
- mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG;
-
- F32 pixels_per_meter = camera->getPixelMeterRatio() / range;
-
- mPixelArea = (pixels_per_meter * max_scale) * (pixels_per_meter * mid_scale);
- if (mPixelArea > camera->getScreenPixelArea())
- {
- mAppAngle = 180.f;
- mPixelArea = (F32)camera->getScreenPixelArea();
- }
- }
-}
-
-BOOL LLViewerObject::updateLOD()
-{
- return FALSE;
-}
-
-BOOL LLViewerObject::updateGeometry(LLDrawable *drawable)
-{
- return TRUE;
-}
-
-void LLViewerObject::updateGL()
-{
-
-}
-
-void LLViewerObject::updateFaceSize(S32 idx)
-{
-
-}
-
-LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline)
-{
- return NULL;
-}
-
-void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped)
-{
- LLPrimitive::setScale(scale);
- if (mDrawable.notNull())
- {
- //encompass completely sheared objects by taking
- //the most extreme point possible (<1,1,0.5>)
- mDrawable->setRadius(LLVector3(1,1,0.5f).scaleVec(scale).magVec());
- updateDrawable(damped);
- }
-
- if( (LL_PCODE_VOLUME == getPCode()) && !isDead() )
- {
- if (permYouOwner() || (scale.magVecSquared() > (7.5f * 7.5f)) )
- {
- if (!mOnMap)
- {
- llassert_always(LLWorld::getInstance()->getRegionFromHandle(getRegion()->getHandle()));
-
- gObjectList.addToMap(this);
- mOnMap = TRUE;
- }
- }
- else
- {
- if (mOnMap)
- {
- gObjectList.removeFromMap(this);
- mOnMap = FALSE;
- }
- }
- }
-}
-
-void LLViewerObject::setObjectCost(F32 cost)
-{
- mObjectCost = cost;
- mCostStale = false;
-
- if (isSelected())
- {
- gFloaterTools->dirty();
- }
-}
-
-void LLViewerObject::setLinksetCost(F32 cost)
-{
- mLinksetCost = cost;
- mCostStale = false;
-
- if (isSelected())
- {
- gFloaterTools->dirty();
- }
-}
-
-void LLViewerObject::setPhysicsCost(F32 cost)
-{
- mPhysicsCost = cost;
- mCostStale = false;
-
- if (isSelected())
- {
- gFloaterTools->dirty();
- }
-}
-
-void LLViewerObject::setLinksetPhysicsCost(F32 cost)
-{
- mLinksetPhysicsCost = cost;
- mCostStale = false;
-
- if (isSelected())
- {
- gFloaterTools->dirty();
- }
-}
-
-
-F32 LLViewerObject::getObjectCost()
-{
- if (mCostStale)
- {
- gObjectList.updateObjectCost(this);
- }
-
- return mObjectCost;
-}
-
-F32 LLViewerObject::getLinksetCost()
-{
- if (mCostStale)
- {
- gObjectList.updateObjectCost(this);
- }
-
- return mLinksetCost;
-}
-
-F32 LLViewerObject::getPhysicsCost()
-{
- if (mCostStale)
- {
- gObjectList.updateObjectCost(this);
- }
-
- return mPhysicsCost;
-}
-
-F32 LLViewerObject::getLinksetPhysicsCost()
-{
- if (mCostStale)
- {
- gObjectList.updateObjectCost(this);
- }
-
- return mLinksetPhysicsCost;
-}
-
-F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes)
-{
- return 0.f;
-}
-
-U32 LLViewerObject::getTriangleCount()
-{
- return 0;
-}
-
-U32 LLViewerObject::getHighLODTriangleCount()
-{
- return 0;
-}
-
-void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
-{
- LLVector4a center;
- center.load3(getRenderPosition().mV);
- LLVector4a size;
- size.load3(getScale().mV);
- newMin.setSub(center, size);
- newMax.setAdd(center, size);
-
- mDrawable->setPositionGroup(center);
-}
-
-F32 LLViewerObject::getBinRadius()
-{
- if (mDrawable.notNull())
- {
- const LLVector4a* ext = mDrawable->getSpatialExtents();
- LLVector4a diff;
- diff.setSub(ext[1], ext[0]);
- return diff.getLength3().getF32();
- }
-
- return getScale().magVec();
-}
-
-F32 LLViewerObject::getMaxScale() const
-{
- return llmax(getScale().mV[VX],getScale().mV[VY], getScale().mV[VZ]);
-}
-
-F32 LLViewerObject::getMinScale() const
-{
- return llmin(getScale().mV[0],getScale().mV[1],getScale().mV[2]);
-}
-
-F32 LLViewerObject::getMidScale() const
-{
- if (getScale().mV[VX] < getScale().mV[VY])
- {
- if (getScale().mV[VY] < getScale().mV[VZ])
- {
- return getScale().mV[VY];
- }
- else if (getScale().mV[VX] < getScale().mV[VZ])
- {
- return getScale().mV[VZ];
- }
- else
- {
- return getScale().mV[VX];
- }
- }
- else if (getScale().mV[VX] < getScale().mV[VZ])
- {
- return getScale().mV[VX];
- }
- else if (getScale().mV[VY] < getScale().mV[VZ])
- {
- return getScale().mV[VZ];
- }
- else
- {
- return getScale().mV[VY];
- }
-}
-
-
-void LLViewerObject::updateTextures()
-{
-}
-
-void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
-{
- if (isDead())
- {
- return;
- }
-
- S32 i;
- S32 tex_count = getNumTEs();
- for (i = 0; i < tex_count; i++)
- {
- getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED);
- }
-
- if (isSculpted() && !isMesh())
- {
- LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
- LLUUID sculpt_id = sculpt_params->getSculptTexture();
- LLViewerTextureManager::getFetchedTexture(sculpt_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLViewerTexture::BOOST_SELECTED);
- }
-
- if (boost_children)
- {
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- child->boostTexturePriority();
- }
- }
-}
-
-
-void LLViewerObject::setLineWidthForWindowSize(S32 window_width)
-{
- if (window_width < 700)
- {
- LLUI::setLineWidth(2.0f);
- }
- else if (window_width < 1100)
- {
- LLUI::setLineWidth(3.0f);
- }
- else if (window_width < 2000)
- {
- LLUI::setLineWidth(4.0f);
- }
- else
- {
- // _damn_, what a nice monitor!
- LLUI::setLineWidth(5.0f);
- }
-}
-
-void LLViewerObject::increaseArrowLength()
-{
-/* ???
- if (mAxisArrowLength == 50)
- {
- mAxisArrowLength = 100;
- }
- else
- {
- mAxisArrowLength = 150;
- }
-*/
-}
-
-
-void LLViewerObject::decreaseArrowLength()
-{
-/* ???
- if (mAxisArrowLength == 150)
- {
- mAxisArrowLength = 100;
- }
- else
- {
- mAxisArrowLength = 50;
- }
-*/
-}
-
-// Culled from newsim LLTask::addNVPair
-void LLViewerObject::addNVPair(const std::string& data)
-{
- // cout << "LLViewerObject::addNVPair() with ---" << data << "---" << endl;
- LLNameValue *nv = new LLNameValue(data.c_str());
-
-// char splat[MAX_STRING];
-// temp->printNameValue(splat);
-// llinfos << "addNVPair " << splat << llendl;
-
- name_value_map_t::iterator iter = mNameValuePairs.find(nv->mName);
- if (iter != mNameValuePairs.end())
- {
- LLNameValue* foundnv = iter->second;
- if (foundnv->mClass != NVC_READ_ONLY)
- {
- delete foundnv;
- mNameValuePairs.erase(iter);
- }
- else
- {
- delete nv;
-// llinfos << "Trying to write to Read Only NVPair " << temp->mName << " in addNVPair()" << llendl;
- return;
- }
- }
- mNameValuePairs[nv->mName] = nv;
-}
-
-BOOL LLViewerObject::removeNVPair(const std::string& name)
-{
- char* canonical_name = gNVNameTable.addString(name);
-
- lldebugs << "LLViewerObject::removeNVPair(): " << name << llendl;
-
- name_value_map_t::iterator iter = mNameValuePairs.find(canonical_name);
- if (iter != mNameValuePairs.end())
- {
- if( mRegionp )
- {
- LLNameValue* nv = iter->second;
-/*
- std::string buffer = nv->printNameValue();
- gMessageSystem->newMessageFast(_PREHASH_RemoveNameValuePair);
- gMessageSystem->nextBlockFast(_PREHASH_TaskData);
- gMessageSystem->addUUIDFast(_PREHASH_ID, mID);
-
- gMessageSystem->nextBlockFast(_PREHASH_NameValueData);
- gMessageSystem->addStringFast(_PREHASH_NVPair, buffer);
-
- gMessageSystem->sendReliable( mRegionp->getHost() );
-*/
- // Remove the NV pair from the local list.
- delete nv;
- mNameValuePairs.erase(iter);
- return TRUE;
- }
- else
- {
- lldebugs << "removeNVPair - No region for object" << llendl;
- }
- }
- return FALSE;
-}
-
-
-LLNameValue *LLViewerObject::getNVPair(const std::string& name) const
-{
- char *canonical_name;
-
- canonical_name = gNVNameTable.addString(name);
-
- // If you access a map with a name that isn't in it, it will add the name and a null pointer.
- // So first check if the data is in the map.
- name_value_map_t::const_iterator iter = mNameValuePairs.find(canonical_name);
- if (iter != mNameValuePairs.end())
- {
- return iter->second;
- }
- else
- {
- return NULL;
- }
-}
-
-void LLViewerObject::updatePositionCaches() const
-{
- if(mRegionp)
- {
- if (!isRoot())
- {
- mPositionRegion = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation();
- mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
- else
- {
- mPositionRegion = getPosition();
- mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
- }
-}
-
-const LLVector3d LLViewerObject::getPositionGlobal() const
-{
- if(mRegionp)
- {
- LLVector3d position_global = mRegionp->getPosGlobalFromRegion(getPositionRegion());
-
- if (isAttachment())
- {
- position_global = gAgent.getPosGlobalFromAgent(getRenderPosition());
- }
- return position_global;
- }
- else
- {
- LLVector3d position_global(getPosition());
- return position_global;
- }
-}
-
-const LLVector3 &LLViewerObject::getPositionAgent() const
-{
- if (mRegionp)
- {
- if (mDrawable.notNull() && (!mDrawable->isRoot() && getParent()))
- {
- // Don't return cached position if you have a parent, recalc (until all dirtying is done correctly.
- LLVector3 position_region;
- position_region = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation();
- mPositionAgent = mRegionp->getPosAgentFromRegion(position_region);
- }
- else
- {
- mPositionAgent = mRegionp->getPosAgentFromRegion(getPosition());
- }
- }
- return mPositionAgent;
-}
-
-const LLVector3 &LLViewerObject::getPositionRegion() const
-{
- if (!isRoot())
- {
- LLViewerObject *parent = (LLViewerObject *)getParent();
- mPositionRegion = parent->getPositionRegion() + (getPosition() * parent->getRotation());
- }
- else
- {
- mPositionRegion = getPosition();
- }
-
- return mPositionRegion;
-}
-
-const LLVector3 LLViewerObject::getPositionEdit() const
-{
- if (isRootEdit())
- {
- return getPosition();
- }
- else
- {
- LLViewerObject *parent = (LLViewerObject *)getParent();
- LLVector3 position_edit = parent->getPositionEdit() + getPosition() * parent->getRotationEdit();
- return position_edit;
- }
-}
-
-const LLVector3 LLViewerObject::getRenderPosition() const
-{
- if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
- {
- LLVOAvatar* avatar = getAvatar();
- if (avatar)
- {
- return avatar->getPositionAgent();
- }
- }
-
- if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
- {
- return getPositionAgent();
- }
- else
- {
- return mDrawable->getPositionAgent();
- }
-}
-
-const LLVector3 LLViewerObject::getPivotPositionAgent() const
-{
- return getRenderPosition();
-}
-
-const LLQuaternion LLViewerObject::getRenderRotation() const
-{
- LLQuaternion ret;
- if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
- {
- return ret;
- }
-
- if (mDrawable.isNull() || mDrawable->isStatic())
- {
- ret = getRotationEdit();
- }
- else
- {
- if (!mDrawable->isRoot())
- {
- ret = getRotation() * LLQuaternion(mDrawable->getParent()->getWorldMatrix());
- }
- else
- {
- ret = LLQuaternion(mDrawable->getWorldMatrix());
- }
- }
-
- return ret;
-}
-
-const LLMatrix4 LLViewerObject::getRenderMatrix() const
-{
- return mDrawable->getWorldMatrix();
-}
-
-const LLQuaternion LLViewerObject::getRotationRegion() const
-{
- LLQuaternion global_rotation = getRotation();
- if (!((LLXform *)this)->isRoot())
- {
- global_rotation = global_rotation * getParent()->getRotation();
- }
- return global_rotation;
-}
-
-const LLQuaternion LLViewerObject::getRotationEdit() const
-{
- LLQuaternion global_rotation = getRotation();
- if (!((LLXform *)this)->isRootEdit())
- {
- global_rotation = global_rotation * getParent()->getRotation();
- }
- return global_rotation;
-}
-
-void LLViewerObject::setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped )
-{
- if (isAttachment())
- {
- LLVector3 new_pos = mRegionp->getPosRegionFromGlobal(pos_global);
- if (isRootEdit())
- {
- new_pos -= mDrawable->mXform.getParent()->getWorldPosition();
- LLQuaternion world_rotation = mDrawable->mXform.getParent()->getWorldRotation();
- new_pos = new_pos * ~world_rotation;
- }
- else
- {
- LLViewerObject* parentp = (LLViewerObject*)getParent();
- new_pos -= parentp->getPositionAgent();
- new_pos = new_pos * ~parentp->getRotationRegion();
- }
- LLViewerObject::setPosition(new_pos);
-
- if (mParent && ((LLViewerObject*)mParent)->isAvatar())
- {
- // we have changed the position of an attachment, so we need to clamp it
- LLVOAvatar *avatar = (LLVOAvatar*)mParent;
-
- avatar->clampAttachmentPositions();
- }
- }
- else
- {
- if( isRoot() )
- {
- setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global));
- }
- else
- {
- // the relative position with the parent is not constant
- LLViewerObject* parent = (LLViewerObject *)getParent();
- //RN: this assumes we are only calling this function from the edit tools
- gPipeline.updateMoveNormalAsync(parent->mDrawable);
-
- LLVector3 pos_local = mRegionp->getPosRegionFromGlobal(pos_global) - parent->getPositionRegion();
- pos_local = pos_local * ~parent->getRotationRegion();
- LLViewerObject::setPosition( pos_local );
- }
- }
- //RN: assumes we always want to snap the object when calling this function
- gPipeline.updateMoveNormalAsync(mDrawable);
-}
-
-void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped)
-{
- if (getPosition() != pos)
- {
- setChanged(TRANSLATED | SILHOUETTE);
- }
-
- LLXform::setPosition(pos);
- updateDrawable(damped);
- if (isRoot())
- {
- // position caches need to be up to date on root objects
- updatePositionCaches();
- }
-}
-
-void LLViewerObject::setPositionGlobal(const LLVector3d &pos_global, BOOL damped)
-{
- if (isAttachment())
- {
- if (isRootEdit())
- {
- LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global);
- newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition();
-
- LLQuaternion invWorldRotation = mDrawable->mXform.getParent()->getWorldRotation();
- invWorldRotation.transQuat();
-
- newPos = newPos * invWorldRotation;
- LLViewerObject::setPosition(newPos);
- }
- else
- {
- // assumes parent is root editable (root of attachment)
- LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global);
- newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition();
- LLVector3 delta_pos = newPos - getPosition();
-
- LLQuaternion invRotation = mDrawable->getRotation();
- invRotation.transQuat();
-
- delta_pos = delta_pos * invRotation;
-
- // *FIX: is this right? Shouldn't we be calling the
- // LLViewerObject version of setPosition?
- LLVector3 old_pos = mDrawable->mXform.getParent()->getPosition();
- mDrawable->mXform.getParent()->setPosition(old_pos + delta_pos);
- setChanged(TRANSLATED | SILHOUETTE);
- }
- if (mParent && ((LLViewerObject*)mParent)->isAvatar())
- {
- // we have changed the position of an attachment, so we need to clamp it
- LLVOAvatar *avatar = (LLVOAvatar*)mParent;
-
- avatar->clampAttachmentPositions();
- }
- }
- else
- {
- if (isRoot())
- {
- setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global));
- }
- else
- {
- // the relative position with the parent is constant, but the parent's position needs to be changed
- LLVector3d position_offset;
- position_offset.setVec(getPosition()*getParent()->getRotation());
- LLVector3d new_pos_global = pos_global - position_offset;
- ((LLViewerObject *)getParent())->setPositionGlobal(new_pos_global);
- }
- }
- updateDrawable(damped);
-}
-
-
-void LLViewerObject::setPositionParent(const LLVector3 &pos_parent, BOOL damped)
-{
- // Set position relative to parent, if no parent, relative to region
- if (!isRoot())
- {
- LLViewerObject::setPosition(pos_parent, damped);
- //updateDrawable(damped);
- }
- else
- {
- setPositionRegion(pos_parent, damped);
- }
-}
-
-void LLViewerObject::setPositionRegion(const LLVector3 &pos_region, BOOL damped)
-{
- if (!isRootEdit())
- {
- LLViewerObject* parent = (LLViewerObject*) getParent();
- LLViewerObject::setPosition((pos_region-parent->getPositionRegion())*~parent->getRotationRegion());
- }
- else
- {
- LLViewerObject::setPosition(pos_region);
- mPositionRegion = pos_region;
- mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
-}
-
-void LLViewerObject::setPositionAgent(const LLVector3 &pos_agent, BOOL damped)
-{
- LLVector3 pos_region = getRegion()->getPosRegionFromAgent(pos_agent);
- setPositionRegion(pos_region, damped);
-}
-
-// identical to setPositionRegion() except it checks for child-joints
-// and doesn't also move the joint-parent
-// TODO -- implement similar intelligence for joint-parents toward
-// their joint-children
-void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped)
-{
- if (!isRootEdit())
- {
- // the relative position with the parent is constant, but the parent's position needs to be changed
- LLVector3 position_offset = getPosition() * getParent()->getRotation();
-
- ((LLViewerObject *)getParent())->setPositionEdit(pos_edit - position_offset);
- updateDrawable(damped);
- }
- else if (isJointChild())
- {
- // compute new parent-relative position
- LLViewerObject *parent = (LLViewerObject *) getParent();
- LLQuaternion inv_parent_rot = parent->getRotation();
- inv_parent_rot.transQuat();
- LLVector3 pos_parent = (pos_edit - parent->getPositionRegion()) * inv_parent_rot;
- LLViewerObject::setPosition(pos_parent, damped);
- }
- else
- {
- LLViewerObject::setPosition(pos_edit, damped);
- mPositionRegion = pos_edit;
- mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
- }
-}
-
-
-LLViewerObject* LLViewerObject::getRootEdit() const
-{
- const LLViewerObject* root = this;
- while (root->mParent
- && !(root->mJointInfo
- || ((LLViewerObject*)root->mParent)->isAvatar()) )
- {
- root = (LLViewerObject*)root->mParent;
- }
- return (LLViewerObject*)root;
-}
-
-
-BOOL LLViewerObject::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
- S32 face,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3* intersection,
- LLVector2* tex_coord,
- LLVector3* normal,
- LLVector3* bi_normal)
-{
- return false;
-}
-
-BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end)
-{
- if (mDrawable.isNull() || mDrawable->isDead())
- {
- return FALSE;
- }
-
- const LLVector4a* ext = mDrawable->getSpatialExtents();
-
- //VECTORIZE THIS
- LLVector4a center;
- center.setAdd(ext[1], ext[0]);
- center.mul(0.5f);
- LLVector4a size;
- size.setSub(ext[1], ext[0]);
- size.mul(0.5f);
-
- LLVector4a starta, enda;
- starta.load3(start.mV);
- enda.load3(end.mV);
-
- return LLLineSegmentBoxIntersect(starta, enda, center, size);
-}
-
-U8 LLViewerObject::getMediaType() const
-{
- if (mMedia)
- {
- return mMedia->mMediaType;
- }
- else
- {
- return LLViewerObject::MEDIA_NONE;
- }
-}
-
-void LLViewerObject::setMediaType(U8 media_type)
-{
- if (!mMedia)
- {
- // TODO what if we don't have a media pointer?
- }
- else if (mMedia->mMediaType != media_type)
- {
- mMedia->mMediaType = media_type;
-
- // TODO: update materials with new image
- }
-}
-
-std::string LLViewerObject::getMediaURL() const
-{
- if (mMedia)
- {
- return mMedia->mMediaURL;
- }
- else
- {
- return std::string();
- }
-}
-
-void LLViewerObject::setMediaURL(const std::string& media_url)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- if (!mMedia)
- {
- mMedia = new LLViewerObjectMedia;
- mMedia->mMediaURL = media_url;
- mMedia->mPassedWhitelist = FALSE;
-
- // TODO: update materials with new image
- }
- else if (mMedia->mMediaURL != media_url)
- {
- mMedia->mMediaURL = media_url;
- mMedia->mPassedWhitelist = FALSE;
-
- // TODO: update materials with new image
- }
-}
-
-BOOL LLViewerObject::getMediaPassedWhitelist() const
-{
- if (mMedia)
- {
- return mMedia->mPassedWhitelist;
- }
- else
- {
- return FALSE;
- }
-}
-
-void LLViewerObject::setMediaPassedWhitelist(BOOL passed)
-{
- if (mMedia)
- {
- mMedia->mPassedWhitelist = passed;
- }
-}
-
-BOOL LLViewerObject::setMaterial(const U8 material)
-{
- BOOL res = LLPrimitive::setMaterial(material);
- if (res)
- {
- setChanged(TEXTURE);
- }
- return res;
-}
-
-void LLViewerObject::setNumTEs(const U8 num_tes)
-{
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- U32 i;
- if (num_tes != getNumTEs())
- {
- if (num_tes)
- {
- LLPointer<LLViewerTexture> *new_images;
- new_images = new LLPointer<LLViewerTexture>[num_tes];
- for (i = 0; i < num_tes; i++)
- {
- if (i < getNumTEs())
- {
- new_images[i] = mTEImages[i];
- }
- else if (getNumTEs())
- {
- new_images[i] = mTEImages[getNumTEs()-1];
- }
- else
- {
- new_images[i] = NULL;
- }
- }
-
- deleteTEImages();
-
- mTEImages = new_images;
- }
- else
- {
- deleteTEImages();
- }
- LLPrimitive::setNumTEs(num_tes);
- setChanged(TEXTURE);
-
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- }
- }
-}
-
-void LLViewerObject::sendMaterialUpdate() const
-{
- LLViewerRegion* regionp = getRegion();
- if(!regionp) return;
- gMessageSystem->newMessageFast(_PREHASH_ObjectMaterial);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
- gMessageSystem->addU8Fast(_PREHASH_Material, getMaterial() );
- gMessageSystem->sendReliable( regionp->getHost() );
-
-}
-
-// formerly send_object_rotation
-void LLViewerObject::sendRotationUpdate() const
-{
- LLViewerRegion* regionp = getRegion();
- if(!regionp) return;
- gMessageSystem->newMessageFast(_PREHASH_ObjectRotation);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID);
- gMessageSystem->addQuatFast(_PREHASH_Rotation, getRotationEdit());
- //llinfos << "Sent rotation " << getRotationEdit() << llendl;
- gMessageSystem->sendReliable( regionp->getHost() );
-}
-
-/* Obsolete, we use MultipleObjectUpdate instead
-//// formerly send_object_position_global
-//void LLViewerObject::sendPositionUpdate() const
-//{
-// gMessageSystem->newMessageFast(_PREHASH_ObjectPosition);
-// gMessageSystem->nextBlockFast(_PREHASH_AgentData);
-// gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
-// gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-// gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
-// gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
-// gMessageSystem->addVector3Fast(_PREHASH_Position, getPositionRegion());
-// LLViewerRegion* regionp = getRegion();
-// gMessageSystem->sendReliable(regionp->getHost());
-//}
-*/
-
-//formerly send_object_shape(LLViewerObject *object)
-void LLViewerObject::sendShapeUpdate()
-{
- gMessageSystem->newMessageFast(_PREHASH_ObjectShape);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
-
- LLVolumeMessage::packVolumeParams(&getVolume()->getParams(), gMessageSystem);
-
- LLViewerRegion *regionp = getRegion();
- gMessageSystem->sendReliable( regionp->getHost() );
-}
-
-
-void LLViewerObject::sendTEUpdate() const
-{
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_ObjectImage);
-
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
- if (mMedia)
- {
- msg->addString("MediaURL", mMedia->mMediaURL);
- }
- else
- {
- msg->addString("MediaURL", NULL);
- }
-
- // TODO send media type
-
- packTEMessage(msg);
-
- LLViewerRegion *regionp = getRegion();
- msg->sendReliable( regionp->getHost() );
-}
-
-void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry)
-{
- LLPrimitive::setTE(te, texture_entry);
-// This doesn't work, don't get any textures.
-// if (mDrawable.notNull() && mDrawable->isVisible())
-// {
- const LLUUID& image_id = getTE(te)->getID();
- mTEImages[te] = LLViewerTextureManager::getFetchedTexture(image_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
-// }
-}
-
-void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep)
-{
- if (mTEImages[te] != imagep)
- {
- mTEImages[te] = imagep;
- LLPrimitive::setTETexture(te, imagep->getID());
- setChanged(TEXTURE);
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- }
- }
-}
-
-
-S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host)
-{
- S32 retval = 0;
- if (uuid != getTE(te)->getID() ||
- uuid == LLUUID::null)
- {
- retval = LLPrimitive::setTETexture(te, uuid);
- mTEImages[te] = LLViewerTextureManager::getFetchedTexture(uuid, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
- setChanged(TEXTURE);
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- return retval;
-}
-
-
-void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image)
-{
- if(index < 0 || index >= getNumTEs())
- {
- return ;
- }
- mTEImages[index] = new_image ;
-}
-
-S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid)
-{
- // Invalid host == get from the agent's sim
- return setTETextureCore(te, uuid, LLHost::invalid);
-}
-
-
-S32 LLViewerObject::setTEColor(const U8 te, const LLColor3& color)
-{
- return setTEColor(te, LLColor4(color));
-}
-
-S32 LLViewerObject::setTEColor(const U8 te, const LLColor4& color)
-{
- S32 retval = 0;
- const LLTextureEntry *tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
- }
- else if (color != tep->getColor())
- {
- retval = LLPrimitive::setTEColor(te, color);
- if (mDrawable.notNull() && retval)
- {
- // These should only happen on updates which are not the initial update.
- dirtyMesh();
- }
- }
- return retval;
-}
-
-S32 LLViewerObject::setTEBumpmap(const U8 te, const U8 bump)
-{
- S32 retval = 0;
- const LLTextureEntry *tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
- }
- else if (bump != tep->getBumpmap())
- {
- retval = LLPrimitive::setTEBumpmap(te, bump);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markTextured(mDrawable);
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
- }
- }
- return retval;
-}
-
-S32 LLViewerObject::setTETexGen(const U8 te, const U8 texgen)
-{
- S32 retval = 0;
- const LLTextureEntry *tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
- }
- else if (texgen != tep->getTexGen())
- {
- retval = LLPrimitive::setTETexGen(te, texgen);
- setChanged(TEXTURE);
- }
- return retval;
-}
-
-S32 LLViewerObject::setTEMediaTexGen(const U8 te, const U8 media)
-{
- S32 retval = 0;
- const LLTextureEntry *tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
- }
- else if (media != tep->getMediaTexGen())
- {
- retval = LLPrimitive::setTEMediaTexGen(te, media);
- setChanged(TEXTURE);
- }
- return retval;
-}
-
-S32 LLViewerObject::setTEShiny(const U8 te, const U8 shiny)
-{
- S32 retval = 0;
- const LLTextureEntry *tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
- }
- else if (shiny != tep->getShiny())
- {
- retval = LLPrimitive::setTEShiny(te, shiny);
- setChanged(TEXTURE);
- }
- return retval;
-}
-
-S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright)
-{
- S32 retval = 0;
- const LLTextureEntry *tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
- }
- else if (fullbright != tep->getFullbright())
- {
- retval = LLPrimitive::setTEFullbright(te, fullbright);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- return retval;
-}
-
-
-S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags)
-{
- // this might need work for media type
- S32 retval = 0;
- const LLTextureEntry *tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
- }
- else if (media_flags != tep->getMediaFlags())
- {
- retval = LLPrimitive::setTEMediaFlags(te, media_flags);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, TRUE);
- gPipeline.markTextured(mDrawable);
- // JC - probably only need this if changes texture coords
- //gPipeline.markRebuild(mDrawable);
- }
- }
- return retval;
-}
-
-S32 LLViewerObject::setTEGlow(const U8 te, const F32 glow)
-{
- S32 retval = 0;
- const LLTextureEntry *tep = getTE(te);
- if (!tep)
- {
- llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
- }
- else if (glow != tep->getGlow())
- {
- retval = LLPrimitive::setTEGlow(te, glow);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markTextured(mDrawable);
- }
- }
- return retval;
-}
-
-
-S32 LLViewerObject::setTEScale(const U8 te, const F32 s, const F32 t)
-{
- S32 retval = 0;
- retval = LLPrimitive::setTEScale(te, s, t);
- setChanged(TEXTURE);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
-}
-
-S32 LLViewerObject::setTEScaleS(const U8 te, const F32 s)
-{
- S32 retval = LLPrimitive::setTEScaleS(te, s);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
-
- return retval;
-}
-
-S32 LLViewerObject::setTEScaleT(const U8 te, const F32 t)
-{
- S32 retval = LLPrimitive::setTEScaleT(te, t);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
-
- return retval;
-}
-
-S32 LLViewerObject::setTEOffset(const U8 te, const F32 s, const F32 t)
-{
- S32 retval = LLPrimitive::setTEOffset(te, s, t);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
-}
-
-S32 LLViewerObject::setTEOffsetS(const U8 te, const F32 s)
-{
- S32 retval = LLPrimitive::setTEOffsetS(te, s);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
-
- return retval;
-}
-
-S32 LLViewerObject::setTEOffsetT(const U8 te, const F32 t)
-{
- S32 retval = LLPrimitive::setTEOffsetT(te, t);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
-
- return retval;
-}
-
-S32 LLViewerObject::setTERotation(const U8 te, const F32 r)
-{
- S32 retval = LLPrimitive::setTERotation(te, r);
- if (mDrawable.notNull() && retval)
- {
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
- }
- return retval;
-}
-
-
-LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const
-{
-// llassert(mTEImages);
-
- if (face < getNumTEs())
- {
- LLViewerTexture* image = mTEImages[face];
- if (image)
- {
- return image;
- }
- else
- {
- return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep);
- }
- }
-
- llerrs << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << llendl;
-
- return NULL;
-}
-
-
-void LLViewerObject::fitFaceTexture(const U8 face)
-{
- llinfos << "fitFaceTexture not implemented" << llendl;
-}
-
-
-LLBBox LLViewerObject::getBoundingBoxAgent() const
-{
- LLVector3 position_agent;
- LLQuaternion rot;
- LLViewerObject* avatar_parent = NULL;
- LLViewerObject* root_edit = (LLViewerObject*)getRootEdit();
- if (root_edit)
- {
- avatar_parent = (LLViewerObject*)root_edit->getParent();
- }
-
- if (avatar_parent && avatar_parent->isAvatar() &&
- root_edit && root_edit->mDrawable.notNull() && root_edit->mDrawable->getXform()->getParent())
- {
- LLXform* parent_xform = root_edit->mDrawable->getXform()->getParent();
- position_agent = (getPositionEdit() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
- rot = getRotationEdit() * parent_xform->getWorldRotation();
- }
- else
- {
- position_agent = getPositionAgent();
- rot = getRotationRegion();
- }
-
- return LLBBox( position_agent, rot, getScale() * -0.5f, getScale() * 0.5f );
-}
-
-U32 LLViewerObject::getNumVertices() const
-{
- U32 num_vertices = 0;
- if (mDrawable.notNull())
- {
- S32 i, num_faces;
- num_faces = mDrawable->getNumFaces();
- for (i = 0; i < num_faces; i++)
- {
- num_vertices += mDrawable->getFace(i)->getGeomCount();
- }
- }
- return num_vertices;
-}
-
-U32 LLViewerObject::getNumIndices() const
-{
- U32 num_indices = 0;
- if (mDrawable.notNull())
- {
- S32 i, num_faces;
- num_faces = mDrawable->getNumFaces();
- for (i = 0; i < num_faces; i++)
- {
- num_indices += mDrawable->getFace(i)->getIndicesCount();
- }
- }
- return num_indices;
-}
-
-// Find the number of instances of this object's inventory that are of the given type
-S32 LLViewerObject::countInventoryContents(LLAssetType::EType type)
-{
- S32 count = 0;
- if( mInventory )
- {
- LLInventoryObject::object_list_t::const_iterator it = mInventory->begin();
- LLInventoryObject::object_list_t::const_iterator end = mInventory->end();
- for( ; it != end ; ++it )
- {
- if( (*it)->getType() == type )
- {
- ++count;
- }
- }
- }
- return count;
-}
-
-
-void LLViewerObject::setCanSelect(BOOL canSelect)
-{
- mbCanSelect = canSelect;
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- child->mbCanSelect = canSelect;
- }
-}
-
-void LLViewerObject::setDebugText(const std::string &utf8text)
-{
- if (utf8text.empty() && !mText)
- {
- return;
- }
-
- if (!mText)
- {
- mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
- mText->setFont(LLFontGL::getFontSansSerif());
- mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
- mText->setMaxLines(-1);
- mText->setSourceObject(this);
- mText->setOnHUDAttachment(isHUDAttachment());
- }
- mText->setColor(LLColor4::white);
- mText->setString(utf8text);
- mText->setZCompare(FALSE);
- mText->setDoFade(FALSE);
- updateText();
-}
-
-void LLViewerObject::setIcon(LLViewerTexture* icon_image)
-{
- if (!mIcon)
- {
- mIcon = (LLHUDIcon *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_ICON);
- mIcon->setSourceObject(this);
- mIcon->setImage(icon_image);
- // *TODO: make this user configurable
- mIcon->setScale(0.03f);
- }
- else
- {
- mIcon->restartLifeTimer();
- }
-}
-
-void LLViewerObject::clearIcon()
-{
- if (mIcon)
- {
- mIcon = NULL;
- }
-}
-
-LLViewerObject* LLViewerObject::getSubParent()
-{
- if (isJointChild())
- {
- return this;
- }
- return (LLViewerObject*) getParent();
-}
-
-const LLViewerObject* LLViewerObject::getSubParent() const
-{
- if (isJointChild())
- {
- return this;
- }
- return (const LLViewerObject*) getParent();
-}
-
-BOOL LLViewerObject::isOnMap()
-{
- return mOnMap;
-}
-
-
-void LLViewerObject::updateText()
-{
- if (!isDead())
- {
- if (mText.notNull())
- {
- LLVector3 up_offset(0,0,0);
- up_offset.mV[2] = getScale().mV[VZ]*0.6f;
-
- if (mDrawable.notNull())
- {
- mText->setPositionAgent(getRenderPosition() + up_offset);
- }
- else
- {
- mText->setPositionAgent(getPositionAgent() + up_offset);
- }
- }
- }
-}
-
-LLVOAvatar* LLViewerObject::asAvatar()
-{
- return NULL;
-}
-
-BOOL LLViewerObject::isParticleSource() const
-{
- return !mPartSourcep.isNull() && !mPartSourcep->isDead();
-}
-
-void LLViewerObject::setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id)
-{
- if (mPartSourcep)
- {
- deleteParticleSource();
- }
-
- LLPointer<LLViewerPartSourceScript> pss = LLViewerPartSourceScript::createPSS(this, particle_parameters);
- mPartSourcep = pss;
-
- if (mPartSourcep)
- {
- mPartSourcep->setOwnerUUID(owner_id);
-
- if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID)
- {
- LLViewerTexture* image;
- if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null)
- {
- image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.tga");
- }
- else
- {
- image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID);
- }
- mPartSourcep->setImage(image);
- }
- }
- LLViewerPartSim::getInstance()->addPartSource(pss);
-}
-
-void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& owner_id)
-{
- if (!mPartSourcep.isNull() && mPartSourcep->isDead())
- {
- mPartSourcep = NULL;
- }
- if (mPartSourcep)
- {
- // If we've got one already, just update the existing source (or remove it)
- if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, block_num))
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
- }
- else
- {
- LLPointer<LLViewerPartSourceScript> pss = LLViewerPartSourceScript::unpackPSS(this, NULL, block_num);
- //If the owner is muted, don't create the system
- if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return;
-
- // We need to be able to deal with a particle source that hasn't changed, but still got an update!
- if (pss)
- {
-// llinfos << "Making particle system with owner " << owner_id << llendl;
- pss->setOwnerUUID(owner_id);
- mPartSourcep = pss;
- LLViewerPartSim::getInstance()->addPartSource(pss);
- }
- }
- if (mPartSourcep)
- {
- if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID)
- {
- LLViewerTexture* image;
- if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null)
- {
- image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c");
- }
- else
- {
- image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID);
- }
- mPartSourcep->setImage(image);
- }
- }
-}
-
-void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id)
-{
- if (!mPartSourcep.isNull() && mPartSourcep->isDead())
- {
- mPartSourcep = NULL;
- }
- if (mPartSourcep)
- {
- // If we've got one already, just update the existing source (or remove it)
- if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, dp))
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
- }
- else
- {
- LLPointer<LLViewerPartSourceScript> pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp);
- //If the owner is muted, don't create the system
- if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return;
- // We need to be able to deal with a particle source that hasn't changed, but still got an update!
- if (pss)
- {
-// llinfos << "Making particle system with owner " << owner_id << llendl;
- pss->setOwnerUUID(owner_id);
- mPartSourcep = pss;
- LLViewerPartSim::getInstance()->addPartSource(pss);
- }
- }
- if (mPartSourcep)
- {
- if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID)
- {
- LLViewerTexture* image;
- if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null)
- {
- image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c");
- }
- else
- {
- image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID);
- }
- mPartSourcep->setImage(image);
- }
- }
-}
-
-void LLViewerObject::deleteParticleSource()
-{
- if (mPartSourcep.notNull())
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
-}
-
-// virtual
-void LLViewerObject::updateDrawable(BOOL force_damped)
-{
- if (mDrawable.notNull() &&
- !mDrawable->isState(LLDrawable::ON_MOVE_LIST) &&
- isChanged(MOVED))
- {
- BOOL damped_motion =
- !isChanged(SHIFTED) && // not shifted between regions this frame and...
- ( force_damped || // ...forced into damped motion by application logic or...
- ( !isSelected() && // ...not selected and...
- ( mDrawable->isRoot() || // ... is root or ...
- (getParent() && !((LLViewerObject*)getParent())->isSelected())// ... parent is not selected and ...
- ) &&
- getPCode() == LL_PCODE_VOLUME && // ...is a volume object and...
- getVelocity().isExactlyZero() && // ...is not moving physically and...
- mDrawable->getGeneration() != -1 // ...was not created this frame.
- )
- );
- gPipeline.markMoved(mDrawable, damped_motion);
- }
- clearChanged(SHIFTED);
-}
-
-// virtual, overridden by LLVOVolume
-F32 LLViewerObject::getVObjRadius() const
-{
- return mDrawable.notNull() ? mDrawable->getRadius() : 0.f;
-}
-
-void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags)
-{
- if (!gAudiop)
- {
- return;
- }
-
- if (audio_uuid.isNull())
- {
- if (!mAudioSourcep)
- {
- return;
- }
- if (mAudioSourcep->isLoop() && !mAudioSourcep->hasPendingPreloads())
- {
- // We don't clear the sound if it's a loop, it'll go away on its own.
- // At least, this appears to be how the scripts work.
- // The attached sound ID is set to NULL to avoid it playing back when the
- // object rezzes in on non-looping sounds.
- //llinfos << "Clearing attached sound " << mAudioSourcep->getCurrentData()->getID() << llendl;
- gAudiop->cleanupAudioSource(mAudioSourcep);
- mAudioSourcep = NULL;
- }
- else if (flags & LL_SOUND_FLAG_STOP)
- {
- // Just shut off the sound
- mAudioSourcep->play(LLUUID::null);
- }
- return;
- }
- if (flags & LL_SOUND_FLAG_LOOP
- && mAudioSourcep && mAudioSourcep->isLoop() && mAudioSourcep->getCurrentData()
- && mAudioSourcep->getCurrentData()->getID() == audio_uuid)
- {
- //llinfos << "Already playing this sound on a loop, ignoring" << llendl;
- return;
- }
-
- // don't clean up before previous sound is done. Solves: SL-33486
- if ( mAudioSourcep && mAudioSourcep->isDone() )
- {
- gAudiop->cleanupAudioSource(mAudioSourcep);
- mAudioSourcep = NULL;
- }
-
- if (mAudioSourcep && mAudioSourcep->isMuted() &&
- mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid)
- {
- //llinfos << "Already having this sound as muted sound, ignoring" << llendl;
- return;
- }
-
- getAudioSource(owner_id);
-
- if (mAudioSourcep)
- {
- BOOL queue = flags & LL_SOUND_FLAG_QUEUE;
- mAudioGain = gain;
- mAudioSourcep->setGain(gain);
- mAudioSourcep->setLoop(flags & LL_SOUND_FLAG_LOOP);
- mAudioSourcep->setSyncMaster(flags & LL_SOUND_FLAG_SYNC_MASTER);
- mAudioSourcep->setSyncSlave(flags & LL_SOUND_FLAG_SYNC_SLAVE);
- mAudioSourcep->setQueueSounds(queue);
- if(!queue) // stop any current sound first to avoid "farts of doom" (SL-1541) -MG
- {
- mAudioSourcep->play(LLUUID::null);
- }
-
- // Play this sound if region maturity permits
- if( gAgent.canAccessMaturityAtGlobal(this->getPositionGlobal()) )
- {
- //llinfos << "Playing attached sound " << audio_uuid << llendl;
- mAudioSourcep->play(audio_uuid);
- }
- }
-}
-
-LLAudioSource *LLViewerObject::getAudioSource(const LLUUID& owner_id)
-{
- if (!mAudioSourcep)
- {
- // Arbitrary low gain for a sound that's not playing.
- // This is used for sound preloads, for example.
- LLAudioSourceVO *asvop = new LLAudioSourceVO(mID, owner_id, 0.01f, this);
-
- mAudioSourcep = asvop;
- if(gAudiop) gAudiop->addAudioSource(asvop);
- }
-
- return mAudioSourcep;
-}
-
-void LLViewerObject::adjustAudioGain(const F32 gain)
-{
- if (!gAudiop)
- {
- return;
- }
- if (mAudioSourcep)
- {
- mAudioGain = gain;
- mAudioSourcep->setGain(mAudioGain);
- }
-}
-
-//----------------------------------------------------------------------------
-
-bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp)
-{
- ExtraParameter* param = getExtraParameterEntryCreate(param_type);
- if (param)
- {
- param->data->unpack(*dp);
- param->in_use = TRUE;
- parameterChanged(param_type, param->data, TRUE, false);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 param_type)
-{
- LLNetworkData* new_block = NULL;
- switch (param_type)
- {
- case LLNetworkData::PARAMS_FLEXIBLE:
- {
- new_block = new LLFlexibleObjectData();
- break;
- }
- case LLNetworkData::PARAMS_LIGHT:
- {
- new_block = new LLLightParams();
- break;
- }
- case LLNetworkData::PARAMS_SCULPT:
- {
- new_block = new LLSculptParams();
- break;
- }
- case LLNetworkData::PARAMS_LIGHT_IMAGE:
- {
- new_block = new LLLightImageParams();
- break;
- }
- default:
- {
- llinfos << "Unknown param type." << llendl;
- break;
- }
- };
-
- if (new_block)
- {
- ExtraParameter* new_entry = new ExtraParameter;
- new_entry->data = new_block;
- new_entry->in_use = false; // not in use yet
- mExtraParameterList[param_type] = new_entry;
- return new_entry;
- }
- return NULL;
-}
-
-LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntry(U16 param_type) const
-{
- std::map<U16, ExtraParameter*>::const_iterator itor = mExtraParameterList.find(param_type);
- if (itor != mExtraParameterList.end())
- {
- return itor->second;
- }
- return NULL;
-}
-
-LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntryCreate(U16 param_type)
-{
- ExtraParameter* param = getExtraParameterEntry(param_type);
- if (!param)
- {
- param = createNewParameterEntry(param_type);
- }
- return param;
-}
-
-LLNetworkData* LLViewerObject::getParameterEntry(U16 param_type) const
-{
- ExtraParameter* param = getExtraParameterEntry(param_type);
- if (param)
- {
- return param->data;
- }
- else
- {
- return NULL;
- }
-}
-
-BOOL LLViewerObject::getParameterEntryInUse(U16 param_type) const
-{
- ExtraParameter* param = getExtraParameterEntry(param_type);
- if (param)
- {
- return param->in_use;
- }
- else
- {
- return FALSE;
- }
-}
-
-bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin)
-{
- ExtraParameter* param = getExtraParameterEntryCreate(param_type);
- if (param)
- {
- if (param->in_use && new_value == *(param->data))
- {
- return false;
- }
- param->in_use = true;
- param->data->copy(new_value);
- parameterChanged(param_type, param->data, TRUE, local_origin);
- return true;
- }
- else
- {
- return false;
- }
-}
-
-// Assumed to be called locally
-// If in_use is TRUE, will crate a new extra parameter if none exists.
-// Should always return true.
-bool LLViewerObject::setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin)
-{
- ExtraParameter* param = getExtraParameterEntryCreate(param_type);
- if (param && param->in_use != in_use)
- {
- param->in_use = in_use;
- parameterChanged(param_type, param->data, in_use, local_origin);
- return true;
- }
- return false;
-}
-
-void LLViewerObject::parameterChanged(U16 param_type, bool local_origin)
-{
- ExtraParameter* param = getExtraParameterEntry(param_type);
- if (param)
- {
- parameterChanged(param_type, param->data, param->in_use, local_origin);
- }
-}
-
-void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin)
-{
- if (local_origin)
- {
- LLViewerRegion* regionp = getRegion();
- if(!regionp) return;
-
- // Change happened on the viewer. Send the change up
- U8 tmp[MAX_OBJECT_PARAMS_SIZE];
- LLDataPackerBinaryBuffer dpb(tmp, MAX_OBJECT_PARAMS_SIZE);
- if (data->pack(dpb))
- {
- U32 datasize = (U32)dpb.getCurrentSize();
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_ObjectExtraParams);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
-
- msg->addU16Fast(_PREHASH_ParamType, param_type);
- msg->addBOOLFast(_PREHASH_ParamInUse, in_use);
-
- msg->addU32Fast(_PREHASH_ParamSize, datasize);
- msg->addBinaryDataFast(_PREHASH_ParamData, tmp, datasize);
-
- msg->sendReliable( regionp->getHost() );
- }
- else
- {
- llwarns << "Failed to send object extra parameters: " << param_type << llendl;
- }
- }
-}
-
-void LLViewerObject::setDrawableState(U32 state, BOOL recursive)
-{
- if (mDrawable)
- {
- mDrawable->setState(state);
- }
- if (recursive)
- {
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- child->setDrawableState(state, recursive);
- }
- }
-}
-
-void LLViewerObject::clearDrawableState(U32 state, BOOL recursive)
-{
- if (mDrawable)
- {
- mDrawable->clearState(state);
- }
- if (recursive)
- {
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- child->clearDrawableState(state, recursive);
- }
- }
-}
-
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// RN: these functions assume a 2-level hierarchy
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-// Owned by anyone?
-BOOL LLViewerObject::permAnyOwner() const
-{
- if (isRootEdit())
- {
- return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0);
- }
- else
- {
- return ((LLViewerObject*)getParent())->permAnyOwner();
- }
-}
-// Owned by this viewer?
-BOOL LLViewerObject::permYouOwner() const
-{
- if (isRootEdit())
- {
-#ifdef HACKED_GODLIKE_VIEWER
- return TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLGridManager::getInstance()->isInProductionGrid()
- && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
- {
- return TRUE;
- }
-# endif
- return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0);
-#endif
- }
- else
- {
- return ((LLViewerObject*)getParent())->permYouOwner();
- }
-}
-
-// Owned by a group?
-BOOL LLViewerObject::permGroupOwner() const
-{
- if (isRootEdit())
- {
- return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0);
- }
- else
- {
- return ((LLViewerObject*)getParent())->permGroupOwner();
- }
-}
-
-// Can the owner edit
-BOOL LLViewerObject::permOwnerModify() const
-{
- if (isRootEdit())
- {
-#ifdef HACKED_GODLIKE_VIEWER
- return TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLGridManager::getInstance()->isInProductionGrid()
- && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
- {
- return TRUE;
- }
-# endif
- return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0);
-#endif
- }
- else
- {
- return ((LLViewerObject*)getParent())->permOwnerModify();
- }
-}
-
-// Can edit
-BOOL LLViewerObject::permModify() const
-{
- if (isRootEdit())
- {
-#ifdef HACKED_GODLIKE_VIEWER
- return TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLGridManager::getInstance()->isInProductionGrid()
- && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
- {
- return TRUE;
- }
-# endif
- return ((mFlags & FLAGS_OBJECT_MODIFY) != 0);
-#endif
- }
- else
- {
- return ((LLViewerObject*)getParent())->permModify();
- }
-}
-
-// Can copy
-BOOL LLViewerObject::permCopy() const
-{
- if (isRootEdit())
- {
-#ifdef HACKED_GODLIKE_VIEWER
- return TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLGridManager::getInstance()->isInProductionGrid()
- && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
- {
- return TRUE;
- }
-# endif
- return ((mFlags & FLAGS_OBJECT_COPY) != 0);
-#endif
- }
- else
- {
- return ((LLViewerObject*)getParent())->permCopy();
- }
-}
-
-// Can move
-BOOL LLViewerObject::permMove() const
-{
- if (isRootEdit())
- {
-#ifdef HACKED_GODLIKE_VIEWER
- return TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLGridManager::getInstance()->isInProductionGrid()
- && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
- {
- return TRUE;
- }
-# endif
- return ((mFlags & FLAGS_OBJECT_MOVE) != 0);
-#endif
- }
- else
- {
- return ((LLViewerObject*)getParent())->permMove();
- }
-}
-
-// Can be transferred
-BOOL LLViewerObject::permTransfer() const
-{
- if (isRootEdit())
- {
-#ifdef HACKED_GODLIKE_VIEWER
- return TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLGridManager::getInstance()->isInProductionGrid()
- && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
- {
- return TRUE;
- }
-# endif
- return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0);
-#endif
- }
- else
- {
- return ((LLViewerObject*)getParent())->permTransfer();
- }
-}
-
-// Can only open objects that you own, or that someone has
-// given you modify rights to. JC
-BOOL LLViewerObject::allowOpen() const
-{
- return !flagInventoryEmpty() && (permYouOwner() || permModify());
-}
-
-LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo()
-{
- if (mListener)
- {
- mListener->clearVOInventoryListener();
- }
-}
-
-void LLViewerObject::updateVolume(const LLVolumeParams& volume_params)
-{
- if (setVolume(volume_params, 1)) // *FIX: magic number, ack!
- {
- // Transmit the update to the simulator
- sendShapeUpdate();
- markForUpdate(TRUE);
- }
-}
-
-void LLViewerObject::markForUpdate(BOOL priority)
-{
- if (mDrawable.notNull())
- {
- gPipeline.markTextured(mDrawable);
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, priority);
- }
-}
-
-bool LLViewerObject::getIncludeInSearch() const
-{
- return ((mFlags & FLAGS_INCLUDE_IN_SEARCH) != 0);
-}
-
-void LLViewerObject::setIncludeInSearch(bool include_in_search)
-{
- if (include_in_search)
- {
- mFlags |= FLAGS_INCLUDE_IN_SEARCH;
- }
- else
- {
- mFlags &= ~FLAGS_INCLUDE_IN_SEARCH;
- }
-}
-
-void LLViewerObject::setRegion(LLViewerRegion *regionp)
-{
- if (!regionp)
- {
- llwarns << "viewer object set region to NULL" << llendl;
- }
-
- mLatestRecvPacketID = 0;
- mRegionp = regionp;
-
- for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i)
- {
- LLViewerObject* child = *i;
- child->setRegion(regionp);
- }
-
- setChanged(MOVED | SILHOUETTE);
- updateDrawable(FALSE);
-}
-
-// virtual
-void LLViewerObject::updateRegion(LLViewerRegion *regionp)
-{
-// if (regionp)
-// {
-// F64 now = LLFrameTimer::getElapsedSeconds();
-// llinfos << "Updating to region " << regionp->getName()
-// << ", ms since last update message: " << (F32)((now - mLastMessageUpdateSecs) * 1000.0)
-// << ", ms since last interpolation: " << (F32)((now - mLastInterpUpdateSecs) * 1000.0)
-// << llendl;
-// }
-}
-
-
-bool LLViewerObject::specialHoverCursor() const
-{
- return (mFlags & FLAGS_USE_PHYSICS)
- || (mFlags & FLAGS_HANDLE_TOUCH)
- || (mClickAction != 0);
-}
-
-void LLViewerObject::updateFlags(BOOL physics_changed)
-{
- LLViewerRegion* regionp = getRegion();
- if(!regionp) return;
- gMessageSystem->newMessage("ObjectFlagUpdate");
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, getLocalID() );
- gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, usePhysics() );
- gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() );
- gMessageSystem->addBOOL("IsPhantom", flagPhantom() );
- gMessageSystem->addBOOL("CastsShadows", flagCastShadows() );
- if (physics_changed)
- {
- gMessageSystem->nextBlock("ExtraPhysics");
- gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() );
- gMessageSystem->addF32("Density", getPhysicsDensity() );
- gMessageSystem->addF32("Friction", getPhysicsFriction() );
- gMessageSystem->addF32("Restitution", getPhysicsRestitution() );
- gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() );
- }
- gMessageSystem->sendReliable( regionp->getHost() );
-}
-
-BOOL LLViewerObject::setFlags(U32 flags, BOOL state)
-{
- BOOL setit = FALSE;
- if (state)
- {
- if ((mFlags & flags) != flags)
- {
- mFlags |= flags;
- setit = TRUE;
- }
- }
- else
- {
- if ((mFlags & flags) != 0)
- {
- mFlags &= ~flags;
- setit = TRUE;
- }
- }
-
- // BUG: Sometimes viewer physics and simulator physics get
- // out of sync. To fix this, always send update to simulator.
-// if (setit)
- {
- updateFlags();
- }
- return setit;
-}
-
-void LLViewerObject::setPhysicsShapeType(U8 type)
-{
- mPhysicsShapeUnknown = false;
- mPhysicsShapeType = type;
- mCostStale = true;
-}
-
-void LLViewerObject::setPhysicsGravity(F32 gravity)
-{
- mPhysicsGravity = gravity;
-}
-
-void LLViewerObject::setPhysicsFriction(F32 friction)
-{
- mPhysicsFriction = friction;
-}
-
-void LLViewerObject::setPhysicsDensity(F32 density)
-{
- mPhysicsDensity = density;
-}
-
-void LLViewerObject::setPhysicsRestitution(F32 restitution)
-{
- mPhysicsRestitution = restitution;
-}
-
-U8 LLViewerObject::getPhysicsShapeType() const
-{
- if (mPhysicsShapeUnknown)
- {
- mPhysicsShapeUnknown = false;
- gObjectList.updatePhysicsFlags(this);
- }
-
- return mPhysicsShapeType;
-}
-
-void LLViewerObject::applyAngularVelocity(F32 dt)
-{
- //do target omega here
- mRotTime += dt;
- LLVector3 ang_vel = getAngularVelocity();
- F32 omega = ang_vel.magVecSquared();
- F32 angle = 0.0f;
- LLQuaternion dQ;
- if (omega > 0.00001f)
- {
- omega = sqrt(omega);
- angle = omega * dt;
-
- ang_vel *= 1.f/omega;
-
- dQ.setQuat(angle, ang_vel);
-
- setRotation(getRotation()*dQ);
- setChanged(MOVED | SILHOUETTE);
- }
-}
-
-void LLViewerObject::resetRot()
-{
- mRotTime = 0.0f;
-}
-
-U32 LLViewerObject::getPartitionType() const
-{
- return LLViewerRegion::PARTITION_NONE;
-}
-
-void LLViewerObject::dirtySpatialGroup(BOOL priority) const
-{
- if (mDrawable)
- {
- LLSpatialGroup* group = mDrawable->getSpatialGroup();
- if (group)
- {
- group->dirtyGeom();
- gPipeline.markRebuild(group, priority);
- }
- }
-}
-
-void LLViewerObject::dirtyMesh()
-{
- if (mDrawable)
- {
- LLSpatialGroup* group = mDrawable->getSpatialGroup();
- if (group)
- {
- group->dirtyMesh();
- }
- }
-}
-
-F32 LLAlphaObject::getPartSize(S32 idx)
-{
- return 0.f;
-}
-
-// virtual
-void LLStaticViewerObject::updateDrawable(BOOL force_damped)
-{
- // Force an immediate rebuild on any update
- if (mDrawable.notNull())
- {
- mDrawable->updateXform(TRUE);
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
- }
- clearChanged(SHIFTED);
-}
-
-void LLViewerObject::saveUnselectedChildrenPosition(std::vector<LLVector3>& positions)
-{
- if(mChildList.empty() || !positions.empty())
- {
- return ;
- }
-
- for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* childp = *iter;
- if (!childp->isSelected() && childp->mDrawable.notNull())
- {
- positions.push_back(childp->getPositionEdit());
- }
- }
-
- return ;
-}
-
-void LLViewerObject::saveUnselectedChildrenRotation(std::vector<LLQuaternion>& rotations)
-{
- if(mChildList.empty())
- {
- return ;
- }
-
- for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* childp = *iter;
- if (!childp->isSelected() && childp->mDrawable.notNull())
- {
- rotations.push_back(childp->getRotationEdit());
- }
- }
-
- return ;
-}
-
-//counter-rotation
-void LLViewerObject::resetChildrenRotationAndPosition(const std::vector<LLQuaternion>& rotations,
- const std::vector<LLVector3>& positions)
-{
- if(mChildList.empty())
- {
- return ;
- }
-
- S32 index = 0 ;
- LLQuaternion inv_rotation = ~getRotationEdit() ;
- LLVector3 offset = getPositionEdit() ;
- for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* childp = *iter;
- if (!childp->isSelected() && childp->mDrawable.notNull())
- {
- if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR)
- {
- childp->setRotation(rotations[index] * inv_rotation);
- childp->setPosition((positions[index] - offset) * inv_rotation);
- LLManip::rebuild(childp);
- }
- else //avatar
- {
- LLVector3 reset_pos = (positions[index] - offset) * inv_rotation ;
- LLQuaternion reset_rot = rotations[index] * inv_rotation ;
-
- ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos);
- ((LLVOAvatar*)childp)->mDrawable->mXform.setRotation(reset_rot) ;
-
- ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE);
- ((LLVOAvatar*)childp)->mDrawable->getVObj()->setRotation(reset_rot, TRUE) ;
-
- LLManip::rebuild(childp);
- }
- index++;
- }
- }
-
- return ;
-}
-
-//counter-translation
-void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified)
-{
- if(mChildList.empty())
- {
- return ;
- }
-
- LLVector3 child_offset;
- if(simplified) //translation only, rotation matrix does not change
- {
- child_offset = offset * ~getRotation();
- }
- else //rotation matrix might change too.
- {
- if (isAttachment() && mDrawable.notNull())
- {
- LLXform* attachment_point_xform = mDrawable->getXform()->getParent();
- LLQuaternion parent_rotation = getRotation() * attachment_point_xform->getWorldRotation();
- child_offset = offset * ~parent_rotation;
- }
- else
- {
- child_offset = offset * ~getRenderRotation();
- }
- }
-
- for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* childp = *iter;
- if (!childp->isSelected() && childp->mDrawable.notNull())
- {
- if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR)
- {
- childp->setPosition(childp->getPosition() + child_offset);
- LLManip::rebuild(childp);
- }
- else //avatar
- {
- LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ;
-
- ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos);
- ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos);
-
- LLManip::rebuild(childp);
- }
- }
- }
-
- return ;
-}
-
-const LLUUID &LLViewerObject::getAttachmentItemID() const
-{
- return mAttachmentItemID;
-}
-
-void LLViewerObject::setAttachmentItemID(const LLUUID &id)
-{
- mAttachmentItemID = id;
-}
-
-EObjectUpdateType LLViewerObject::getLastUpdateType() const
-{
- return mLastUpdateType;
-}
-
-void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type)
-{
- mLastUpdateType = last_update_type;
-}
-
-BOOL LLViewerObject::getLastUpdateCached() const
-{
- return mLastUpdateCached;
-}
-
-void LLViewerObject::setLastUpdateCached(BOOL last_update_cached)
-{
- mLastUpdateCached = last_update_cached;
-}
-
-const LLUUID &LLViewerObject::extractAttachmentItemID()
-{
- LLUUID item_id = LLUUID::null;
- LLNameValue* item_id_nv = getNVPair("AttachItemID");
- if( item_id_nv )
- {
- const char* s = item_id_nv->getString();
- if( s )
- {
- item_id.set(s);
- }
- }
- setAttachmentItemID(item_id);
- return getAttachmentItemID();
-}
-
-//virtual
-LLVOAvatar* LLViewerObject::getAvatar() const
-{
- if (isAttachment())
- {
- LLViewerObject* vobj = (LLViewerObject*) getParent();
-
- while (vobj && !vobj->asAvatar())
- {
- vobj = (LLViewerObject*) vobj->getParent();
- }
-
- return (LLVOAvatar*) vobj;
- }
-
- return NULL;
-}
-
-
-class ObjectPhysicsProperties : public LLHTTPNode
-{
-public:
- virtual void post(
- ResponsePtr responder,
- const LLSD& context,
- const LLSD& input) const
- {
- LLSD object_data = input["body"]["ObjectData"];
- S32 num_entries = object_data.size();
-
- for ( S32 i = 0; i < num_entries; i++ )
- {
- LLSD& curr_object_data = object_data[i];
- U32 local_id = curr_object_data["LocalID"].asInteger();
-
- // Iterate through nodes at end, since it can be on both the regular AND hover list
- struct f : public LLSelectedNodeFunctor
- {
- U32 mID;
- f(const U32& id) : mID(id) {}
- virtual bool apply(LLSelectNode* node)
- {
- return (node->getObject() && node->getObject()->mLocalID == mID );
- }
- } func(local_id);
-
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func);
-
- if (node)
- {
- // The LLSD message builder doesn't know how to handle U8, so we need to send as S8 and cast
- U8 type = (U8)curr_object_data["PhysicsShapeType"].asInteger();
- F32 density = (F32)curr_object_data["Density"].asReal();
- F32 friction = (F32)curr_object_data["Friction"].asReal();
- F32 restitution = (F32)curr_object_data["Restitution"].asReal();
- F32 gravity = (F32)curr_object_data["GravityMultiplier"].asReal();
-
- node->getObject()->setPhysicsShapeType(type);
- node->getObject()->setPhysicsGravity(gravity);
- node->getObject()->setPhysicsFriction(friction);
- node->getObject()->setPhysicsDensity(density);
- node->getObject()->setPhysicsRestitution(restitution);
- }
- }
-
- dialog_refresh_all();
- };
-};
-
-LLHTTPRegistration<ObjectPhysicsProperties>
- gHTTPRegistrationObjectPhysicsProperties("/message/ObjectPhysicsProperties");
-
-
-void LLViewerObject::updateQuota( const SelectionQuota& quota )
-{
- //update quotas
- mSelectionQuota = quota;
-}
+/** + * @file llviewerobject.cpp + * @brief Base class for viewer objects + * + * $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 "llviewerobject.h" + +#include "llaudioengine.h" +#include "imageids.h" +#include "indra_constants.h" +#include "llmath.h" +#include "llflexibleobject.h" +#include "llviewercontrol.h" +#include "lldatapacker.h" +#include "llfasttimer.h" +#include "llfloaterreg.h" +#include "llfontgl.h" +#include "llframetimer.h" +#include "llinventory.h" +#include "llinventorydefines.h" +#include "llmaterialtable.h" +#include "llmutelist.h" +#include "llnamevalue.h" +#include "llprimitive.h" +#include "llquantize.h" +#include "llregionhandle.h" +#include "llsdserialize.h" +#include "lltree_common.h" +#include "llxfermanager.h" +#include "message.h" +#include "object_flags.h" +#include "timing.h" + +#include "llaudiosourcevo.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llbbox.h" +#include "llbox.h" +#include "llcylinder.h" +#include "lldrawable.h" +#include "llface.h" +#include "llfloaterproperties.h" +#include "llfloatertools.h" +#include "llfollowcam.h" +#include "llhudtext.h" +#include "llselectmgr.h" +#include "llrendersphere.h" +#include "lltooldraganddrop.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewerinventory.h" +#include "llviewerobjectlist.h" +#include "llviewerparceloverlay.h" +#include "llviewerpartsource.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llviewertextureanim.h" +#include "llviewerwindow.h" // For getSpinAxis +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llvoclouds.h" +#include "llvograss.h" +#include "llvoground.h" +#include "llvolume.h" +#include "llvolumemessage.h" +#include "llvopartgroup.h" +#include "llvosky.h" +#include "llvosurfacepatch.h" +#include "llvotextbubble.h" +#include "llvotree.h" +#include "llvovolume.h" +#include "llvowater.h" +#include "llworld.h" +#include "llui.h" +#include "pipeline.h" +#include "llviewernetwork.h" +#include "llvowlsky.h" +#include "llmanip.h" +#include "lltrans.h" +#include "llsdutil.h" +#include "llmediaentry.h" +#include "llaccountingquota.h" + +//#define DEBUG_UPDATE_TYPE + +BOOL LLViewerObject::sVelocityInterpolate = TRUE; +BOOL LLViewerObject::sPingInterpolate = TRUE; + +U32 LLViewerObject::sNumZombieObjects = 0; +S32 LLViewerObject::sNumObjects = 0; +BOOL LLViewerObject::sMapDebug = TRUE; +LLColor4 LLViewerObject::sEditSelectColor( 1.0f, 1.f, 0.f, 0.3f); // Edit OK +LLColor4 LLViewerObject::sNoEditSelectColor( 1.0f, 0.f, 0.f, 0.3f); // Can't edit +S32 LLViewerObject::sAxisArrowLength(50); +BOOL LLViewerObject::sPulseEnabled(FALSE); +BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE + +// sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime +F64 LLViewerObject::sMaxUpdateInterpolationTime = 3.0; // For motion interpolation: after X seconds with no updates, don't predict object motion +F64 LLViewerObject::sPhaseOutUpdateInterpolationTime = 2.0; // For motion interpolation: after Y seconds with no updates, taper off motion prediction + + +static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); + +// static +LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) +{ + LLViewerObject *res = NULL; + LLFastTimer t1(FTM_CREATE_OBJECT); + + switch (pcode) + { + case LL_PCODE_VOLUME: + res = new LLVOVolume(id, pcode, regionp); break; + case LL_PCODE_LEGACY_AVATAR: + { + if (id == gAgentID) + { + if (!gAgentAvatarp) + { + gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp); + } + else + { + gAgentAvatarp->updateRegion(regionp); + } + res = gAgentAvatarp; + } + else + { + res = new LLVOAvatar(id, pcode, regionp); + } + static_cast<LLVOAvatar*>(res)->initInstance(); + break; + } + case LL_PCODE_LEGACY_GRASS: + res = new LLVOGrass(id, pcode, regionp); break; + case LL_PCODE_LEGACY_PART_SYS: +// llwarns << "Creating old part sys!" << llendl; +// res = new LLVOPart(id, pcode, regionp); break; + res = NULL; break; + case LL_PCODE_LEGACY_TREE: + res = new LLVOTree(id, pcode, regionp); break; + case LL_PCODE_TREE_NEW: +// llwarns << "Creating new tree!" << llendl; +// res = new LLVOTree(id, pcode, regionp); break; + res = NULL; break; + case LL_PCODE_LEGACY_TEXT_BUBBLE: + res = new LLVOTextBubble(id, pcode, regionp); break; + case LL_VO_CLOUDS: + res = new LLVOClouds(id, pcode, regionp); break; + case LL_VO_SURFACE_PATCH: + res = new LLVOSurfacePatch(id, pcode, regionp); break; + case LL_VO_SKY: + res = new LLVOSky(id, pcode, regionp); break; + case LL_VO_VOID_WATER: + res = new LLVOVoidWater(id, pcode, regionp); break; + case LL_VO_WATER: + res = new LLVOWater(id, pcode, regionp); break; + case LL_VO_GROUND: + res = new LLVOGround(id, pcode, regionp); break; + case LL_VO_PART_GROUP: + res = new LLVOPartGroup(id, pcode, regionp); break; + case LL_VO_HUD_PART_GROUP: + res = new LLVOHUDPartGroup(id, pcode, regionp); break; + case LL_VO_WL_SKY: + res = new LLVOWLSky(id, pcode, regionp); break; + default: + llwarns << "Unknown object pcode " << (S32)pcode << llendl; + res = NULL; break; + } + return res; +} + +LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global) +: LLPrimitive(), + mChildList(), + mID(id), + mLocalID(0), + mTotalCRC(0), + mTEImages(NULL), + mGLName(0), + mbCanSelect(TRUE), + mFlags(0), + mPhysicsShapeType(0), + mPhysicsGravity(0), + mPhysicsFriction(0), + mPhysicsDensity(0), + mPhysicsRestitution(0), + mDrawable(), + mCreateSelected(FALSE), + mRenderMedia(FALSE), + mBestUpdatePrecision(0), + mText(), + mLastInterpUpdateSecs(0.f), + mLastMessageUpdateSecs(0.f), + mLatestRecvPacketID(0), + mData(NULL), + mAudioSourcep(NULL), + mAudioGain(1.f), + mAppAngle(0.f), + mPixelArea(1024.f), + mInventory(NULL), + mInventorySerialNum(0), + mRegionp( regionp ), + mInventoryPending(FALSE), + mInventoryDirty(FALSE), + mDead(FALSE), + mOrphaned(FALSE), + mUserSelected(FALSE), + mOnActiveList(FALSE), + mOnMap(FALSE), + mStatic(FALSE), + mNumFaces(0), + mTimeDilation(1.f), + mRotTime(0.f), + mJointInfo(NULL), + mState(0), + mMedia(NULL), + mClickAction(0), + mObjectCost(0), + mLinksetCost(0), + mPhysicsCost(0), + mLinksetPhysicsCost(0.f), + mCostStale(true), + mPhysicsShapeUnknown(true), + mAttachmentItemID(LLUUID::null), + mLastUpdateType(OUT_UNKNOWN), + mLastUpdateCached(FALSE) +{ + if (!is_global) + { + llassert(mRegionp); + } + + LLPrimitive::init_primitive(pcode); + + // CP: added 12/2/2005 - this was being initialised to 0, not the current frame time + mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds(); + + mPositionRegion = LLVector3(0.f, 0.f, 0.f); + + if (!is_global && mRegionp) + { + mPositionAgent = mRegionp->getOriginAgent(); + } + + LLViewerObject::sNumObjects++; +} + +LLViewerObject::~LLViewerObject() +{ + deleteTEImages(); + + if(mInventory) + { + mInventory->clear(); // will deref and delete entries + delete mInventory; + mInventory = NULL; + } + + if (mJointInfo) + { + delete mJointInfo; + mJointInfo = NULL; + } + + if (mPartSourcep) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } + + // Delete memory associated with extra parameters. + std::map<U16, ExtraParameter*>::iterator iter; + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + if(iter->second != NULL) + { + delete iter->second->data; + delete iter->second; + } + } + mExtraParameterList.clear(); + + for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; + mNameValuePairs.clear(); + + delete[] mData; + mData = NULL; + + delete mMedia; + mMedia = NULL; + + sNumObjects--; + sNumZombieObjects--; + llassert(mChildList.size() == 0); + + clearInventoryListeners(); +} + +void LLViewerObject::deleteTEImages() +{ + delete[] mTEImages; + mTEImages = NULL; +} + +void LLViewerObject::markDead() +{ + if (!mDead) + { + //llinfos << "Marking self " << mLocalID << " as dead." << llendl; + + // Root object of this hierarchy unlinks itself. + if (getParent()) + { + ((LLViewerObject *)getParent())->removeChild(this); + // go ahead and delete any jointinfo's that we find + delete mJointInfo; + mJointInfo = NULL; + } + + // Mark itself as dead + mDead = TRUE; + gObjectList.cleanupReferences(this); + + LLViewerObject *childp; + while (mChildList.size() > 0) + { + childp = mChildList.back(); + if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) + { + //llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl; + childp->setParent(NULL); // LLViewerObject::markDead 1 + childp->markDead(); + } + else + { + // make sure avatar is no longer parented, + // so we can properly set it's position + childp->setDrawableParent(NULL); + ((LLVOAvatar*)childp)->getOffObject(); + childp->setParent(NULL); // LLViewerObject::markDead 2 + } + mChildList.pop_back(); + } + + if (mDrawable.notNull()) + { + // Drawables are reference counted, mark as dead, then nuke the pointer. + mDrawable->markDead(); + mDrawable = NULL; + } + + if (mText) + { + mText->markDead(); + mText = NULL; + } + + if (mIcon) + { + mIcon->markDead(); + mIcon = NULL; + } + + if (mPartSourcep) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } + + if (mAudioSourcep) + { + // Do some cleanup + if (gAudiop) + { + gAudiop->cleanupAudioSource(mAudioSourcep); + } + mAudioSourcep = NULL; + } + + if (flagAnimSource()) + { + if (isAgentAvatarValid()) + { + // stop motions associated with this object + gAgentAvatarp->stopMotionFromSource(mID); + } + } + + if (flagCameraSource()) + { + LLFollowCamMgr::removeFollowCamParams(mID); + } + + sNumZombieObjects++; + } +} + +void LLViewerObject::dump() const +{ + llinfos << "Type: " << pCodeToString(mPrimitiveCode) << llendl; + llinfos << "Drawable: " << (LLDrawable *)mDrawable << llendl; + llinfos << "Update Age: " << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs << llendl; + + llinfos << "Parent: " << getParent() << llendl; + llinfos << "ID: " << mID << llendl; + llinfos << "LocalID: " << mLocalID << llendl; + llinfos << "PositionRegion: " << getPositionRegion() << llendl; + llinfos << "PositionAgent: " << getPositionAgent() << llendl; + llinfos << "PositionGlobal: " << getPositionGlobal() << llendl; + llinfos << "Velocity: " << getVelocity() << llendl; + if (mDrawable.notNull() && mDrawable->getNumFaces()) + { + LLFacePool *poolp = mDrawable->getFace(0)->getPool(); + if (poolp) + { + llinfos << "Pool: " << poolp << llendl; + llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl; + } + } + //llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl; + //llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl; + /* + llinfos << "Velocity: " << getVelocity() << llendl; + llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl; + llinfos << "UsePhysics: " << usePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl; + llinfos << "AppAngle: " << mAppAngle << llendl; + llinfos << "PixelArea: " << mPixelArea << llendl; + + char buffer[1000]; + char *key; + for (key = mNameValuePairs.getFirstKey(); key; key = mNameValuePairs.getNextKey() ) + { + mNameValuePairs[key]->printNameValue(buffer); + llinfos << buffer << llendl; + } + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + llinfos << " child " << child->getID() << llendl; + } + */ +} + +void LLViewerObject::printNameValuePairs() const +{ + for (name_value_map_t::const_iterator iter = mNameValuePairs.begin(); + iter != mNameValuePairs.end(); iter++) + { + LLNameValue* nv = iter->second; + llinfos << nv->printNameValue() << llendl; + } +} + +void LLViewerObject::initVOClasses() +{ + // Initialized shared class stuff first. + LLVOAvatar::initClass(); + LLVOTree::initClass(); + llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl; + LLVOGrass::initClass(); + LLVOWater::initClass(); + LLVOVolume::initClass(); +} + +void LLViewerObject::cleanupVOClasses() +{ + LLVOGrass::cleanupClass(); + LLVOWater::cleanupClass(); + LLVOTree::cleanupClass(); + LLVOAvatar::cleanupClass(); + LLVOVolume::cleanupClass(); +} + +// Replaces all name value pairs with data from \n delimited list +// Does not update server +void LLViewerObject::setNameValueList(const std::string& name_value_list) +{ + // Clear out the old + for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; + mNameValuePairs.clear(); + + // Bring in the new + std::string::size_type length = name_value_list.length(); + std::string::size_type start = 0; + while (start < length) + { + std::string::size_type end = name_value_list.find_first_of("\n", start); + if (end == std::string::npos) end = length; + if (end > start) + { + std::string tok = name_value_list.substr(start, end - start); + addNVPair(tok); + } + start = end+1; + } +} + + +// This method returns true if the object is over land owned by the +// agent. +bool LLViewerObject::isReturnable() +{ + if (isAttachment()) + { + return false; + } + std::vector<LLBBox> boxes; + boxes.push_back(LLBBox(getPositionRegion(), getRotationRegion(), getScale() * -0.5f, getScale() * 0.5f).getAxisAligned()); + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + boxes.push_back(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned()); + } + + return mRegionp + && mRegionp->objectIsReturnable(getPositionRegion(), boxes); +} + +BOOL LLViewerObject::setParent(LLViewerObject* parent) +{ + if(mParent != parent) + { + LLViewerObject* old_parent = (LLViewerObject*)mParent ; + BOOL ret = LLPrimitive::setParent(parent); + if(ret && old_parent && parent) + { + old_parent->removeChild(this) ; + } + return ret ; + } + + return FALSE ; +} + +void LLViewerObject::addChild(LLViewerObject *childp) +{ + for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) + { + if (*i == childp) + { //already has child + return; + } + } + + if (!isAvatar()) + { + // propagate selection properties + childp->mbCanSelect = mbCanSelect; + } + + if(childp->setParent(this)) + { + mChildList.push_back(childp); + } +} + +void LLViewerObject::removeChild(LLViewerObject *childp) +{ + for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) + { + if (*i == childp) + { + if (!childp->isAvatar() && mDrawable.notNull() && mDrawable->isActive() && childp->mDrawable.notNull() && !isAvatar()) + { + gPipeline.markRebuild(childp->mDrawable, LLDrawable::REBUILD_VOLUME); + } + + mChildList.erase(i); + + if(childp->getParent() == this) + { + childp->setParent(NULL); + } + break; + } + } + + if (childp->isSelected()) + { + LLSelectMgr::getInstance()->deselectObjectAndFamily(childp); + BOOL add_to_end = TRUE; + LLSelectMgr::getInstance()->selectObjectAndFamily(childp, add_to_end); + } +} + +void LLViewerObject::addThisAndAllChildren(std::vector<LLViewerObject*>& objects) +{ + objects.push_back(this); + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + if (!child->isAvatar()) + { + child->addThisAndAllChildren(objects); + } + } +} + +void LLViewerObject::addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects) +{ + objects.push_back(this); + // don't add any attachments when temporarily selecting avatar + if (isAvatar()) + { + return; + } + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + if ( (!child->isAvatar()) && (!child->isJointChild())) + { + child->addThisAndNonJointChildren(objects); + } + } +} + +BOOL LLViewerObject::isChild(LLViewerObject *childp) const +{ + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* testchild = *iter; + if (testchild == childp) + return TRUE; + } + return FALSE; +} + + +// returns TRUE if at least one avatar is sitting on this object +BOOL LLViewerObject::isSeat() const +{ + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + if (child->isAvatar()) + { + return TRUE; + } + } + return FALSE; + +} + +BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) +{ + if (mDrawable.isNull()) + { + return FALSE; + } + + BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL); + if(!ret) + { + return FALSE ; + } + LLDrawable* old_parent = mDrawable->mParent; + mDrawable->mParent = parentp; + + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + if( (old_parent != parentp && old_parent) + || (parentp && parentp->isActive())) + { + // *TODO we should not be relying on setDrawable parent to call markMoved + gPipeline.markMoved(mDrawable, FALSE); + } + else if (!mDrawable->isAvatar()) + { + mDrawable->updateXform(TRUE); + /*if (!mDrawable->getSpatialGroup()) + { + mDrawable->movePartition(); + }*/ + } + + return ret; +} + +// Show or hide particles, icon and HUD +void LLViewerObject::hideExtraDisplayItems( BOOL hidden ) +{ + if( mPartSourcep.notNull() ) + { + LLViewerPartSourceScript *partSourceScript = mPartSourcep.get(); + partSourceScript->setSuspended( hidden ); + } + + if( mText.notNull() ) + { + LLHUDText *hudText = mText.get(); + hudText->setHidden( hidden ); + } + + if( mIcon.notNull() ) + { + LLHUDIcon *hudIcon = mIcon.get(); + hudIcon->setHidden( hidden ); + } +} + +U32 LLViewerObject::checkMediaURL(const std::string &media_url) +{ + U32 retval = (U32)0x0; + if (!mMedia && !media_url.empty()) + { + retval |= MEDIA_URL_ADDED; + mMedia = new LLViewerObjectMedia; + mMedia->mMediaURL = media_url; + mMedia->mMediaType = LLViewerObject::MEDIA_SET; + mMedia->mPassedWhitelist = FALSE; + } + else if (mMedia) + { + if (media_url.empty()) + { + retval |= MEDIA_URL_REMOVED; + delete mMedia; + mMedia = NULL; + } + else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. + { + /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && + LLTextureEntry::getVersionFromMediaVersionString(media_url) == + LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) + */ + { + // If the media URL is different and WE were not the one who + // changed it, mark dirty. + retval |= MEDIA_URL_UPDATED; + } + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + } + } + return retval; +} + +U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + U32 retval = 0x0; + + // Coordinates of objects on simulators are region-local. + U64 region_handle; + mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + + { + LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); + if(regionp != mRegionp && regionp && mRegionp)//region cross + { + //this is the redundant position and region update, but it is necessary in case the viewer misses the following + //position and region update messages from sim. + //this redundant update should not cause any problems. + LLVector3 delta_pos = mRegionp->getOriginAgent() - regionp->getOriginAgent(); + setPositionParent(getPosition() + delta_pos); //update to the new region position immediately. + setRegion(regionp) ; //change the region. + } + else + { + mRegionp = regionp ; + } + } + + if (!mRegionp) + { + U32 x, y; + from_region_handle(region_handle, &x, &y); + + llerrs << "Object has invalid region " << x << ":" << y << "!" << llendl; + return retval; + } + + U16 time_dilation16; + mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); + F32 time_dilation = ((F32) time_dilation16) / 65535.f; + mTimeDilation = time_dilation; + mRegionp->setTimeDilation(time_dilation); + + // this will be used to determine if we've really changed position + // Use getPosition, not getPositionRegion, since this is what we're comparing directly against. + LLVector3 test_pos_parent = getPosition(); + + U8 data[60+16]; // This needs to match the largest size below. +#ifdef LL_BIG_ENDIAN + U16 valswizzle[4]; +#endif + U16 *val; + const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); + const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight(); + const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight(); + S32 length; + S32 count; + S32 this_update_precision = 32; // in bits + + // Temporaries, because we need to compare w/ previous to set dirty flags... + LLVector3 new_pos_parent; + LLVector3 new_vel; + LLVector3 new_acc; + LLVector3 new_angv; + LLVector3 old_angv = getAngularVelocity(); + LLQuaternion new_rot; + LLVector3 new_scale = getScale(); + + U32 parent_id = 0; + U8 material = 0; + U8 click_action = 0; + U32 crc = 0; + + bool old_special_hover_cursor = specialHoverCursor(); + + LLViewerObject *cur_parentp = (LLViewerObject *)getParent(); + + if (cur_parentp) + { + parent_id = cur_parentp->mLocalID; + } + + if (!dp) + { + switch(update_type) + { + case OUT_FULL: + { +#ifdef DEBUG_UPDATE_TYPE + llinfos << "Full:" << getID() << llendl; +#endif + //clear cost and linkset cost + mCostStale = true; + if (isSelected()) + { + gFloaterTools->dirty(); + } + + LLUUID audio_uuid; + LLUUID owner_id; // only valid if audio_uuid or particle system is not null + F32 gain; + U8 sound_flags; + + mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num); + mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_ParentID, parent_id, block_num); + mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound, audio_uuid, block_num ); + // HACK: Owner id only valid if non-null sound id or particle system + mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num ); + mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); + mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num ); + length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); + + mTotalCRC = crc; + + // Owner ID used for sound muting or particle system muting + setAttachedSound(audio_uuid, owner_id, gain, sound_flags); + + U8 old_material = getMaterial(); + if (old_material != material) + { + setMaterial(material); + if (mDrawable.notNull()) + { + gPipeline.markMoved(mDrawable, FALSE); // undamped + } + } + setClickAction(click_action); + + count = 0; + LLVector4 collision_plane; + + switch(length) + { + case (60 + 16): + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 60: + this_update_precision = 32; + // this is a terse update + // pos + htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // vel + htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // acc + htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // theta + { + LLVector3 vec; + htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + new_rot.unpackFromVector3(vec); + } + count += sizeof(LLVector3); + // omega + htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); +#if LL_DARWIN + if (length == 76) + { + setAngularVelocity(LLVector3::zero); + } +#endif + break; + case(32 + 16): + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 32: + this_update_precision = 16; + test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + + // This is a terse 16 update, so treat data as an array of U16's. +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + setVelocity(LLVector3(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size))); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size))); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*4; + new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); + new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); + new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); + new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + new_angv.setVec(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); + break; + + case 16: + this_update_precision = 8; + test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + // this is a terse 8 update + new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); + + setVelocity(U8_to_F32(data[3], -size, size), + U8_to_F32(data[4], -size, size), + U8_to_F32(data[5], -size, size) ); + + setAcceleration(U8_to_F32(data[6], -size, size), + U8_to_F32(data[7], -size, size), + U8_to_F32(data[8], -size, size) ); + + new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); + new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); + new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); + new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); + + new_angv.setVec(U8_to_F32(data[13], -size, size), + U8_to_F32(data[14], -size, size), + U8_to_F32(data[15], -size, size) ); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); + break; + } + + //////////////////////////////////////////////////// + // + // Here we handle data specific to the full message. + // + + U32 flags; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); + // clear all but local flags + mFlags &= FLAGS_LOCAL; + mFlags |= flags; + + U8 state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); + mState = state; + + // ...new objects that should come in selected need to be added to the selected list + mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + + // Set all name value pairs + S32 nv_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_NameValue); + if (nv_size > 0) + { + std::string name_value_list; + mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_NameValue, name_value_list, block_num); + setNameValueList(name_value_list); + } + + // Clear out any existing generic data + if (mData) + { + delete [] mData; + } + + // Check for appended generic data + S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Data); + if (data_size <= 0) + { + mData = NULL; + } + else + { + // ...has generic data + mData = new U8[data_size]; + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, mData, data_size, block_num); + } + + S32 text_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Text); + if (text_size > 1) + { + // Setup object text + if (!mText) + { + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); + } + + std::string temp_string; + mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, temp_string, block_num ); + + LLColor4U coloru; + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num); + + // alpha was flipped so that it zero encoded better + coloru.mV[3] = 255 - coloru.mV[3]; + mText->setColor(LLColor4(coloru)); + mText->setString(temp_string); + + if (mDrawable.notNull()) + { + setChanged(MOVED | SILHOUETTE); + gPipeline.markMoved(mDrawable, FALSE); // undamped + } + } + else if (mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + + std::string media_url; + mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num); + retval |= checkMediaURL(media_url); + + // + // Unpack particle system data + // + unpackParticleSource(block_num, owner_id); + + // Mark all extra parameters not used + std::map<U16, ExtraParameter*>::iterator iter; + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + iter->second->in_use = FALSE; + } + + // Unpack extra parameters + S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ExtraParams); + if (size > 0) + { + U8 *buffer = new U8[size]; + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ExtraParams, buffer, size, block_num); + LLDataPackerBinaryBuffer dp(buffer, size); + + U8 num_parameters; + dp.unpackU8(num_parameters, "num_params"); + U8 param_block[MAX_OBJECT_PARAMS_SIZE]; + for (U8 param=0; param<num_parameters; ++param) + { + U16 param_type; + S32 param_size; + dp.unpackU16(param_type, "param_type"); + dp.unpackBinaryData(param_block, param_size, "param_data"); + //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl; + LLDataPackerBinaryBuffer dp2(param_block, param_size); + unpackParameterEntry(param_type, &dp2); + } + delete[] buffer; + } + + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + if (!iter->second->in_use) + { + // Send an update message in case it was formerly in use + parameterChanged(iter->first, iter->second->data, FALSE, false); + } + } + + U8 joint_type = 0; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_JointType, joint_type, block_num); + if (joint_type) + { + // create new joint info + if (!mJointInfo) + { + mJointInfo = new LLVOJointInfo; + } + mJointInfo->mJointType = (EHavokJointType) joint_type; + mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointPivot, mJointInfo->mPivot, block_num); + mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointAxisOrAnchor, mJointInfo->mAxisOrAnchor, block_num); + } + else if (mJointInfo) + { + // this joint info is no longer needed + delete mJointInfo; + mJointInfo = NULL; + } + + break; + } + + case OUT_TERSE_IMPROVED: + { +#ifdef DEBUG_UPDATE_TYPE + llinfos << "TI:" << getID() << llendl; +#endif + length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); + count = 0; + LLVector4 collision_plane; + + switch(length) + { + case(60 + 16): + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 60: + // this is a terse 32 update + // pos + this_update_precision = 32; + htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // vel + htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // acc + htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // theta + { + LLVector3 vec; + htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + new_rot.unpackFromVector3(vec); + } + count += sizeof(LLVector3); + // omega + htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); +#if LL_DARWIN + if (length == 76) + { + setAngularVelocity(LLVector3::zero); + } +#endif + break; + case(32 + 16): + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 32: + // this is a terse 16 update + this_update_precision = 16; + test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + setVelocity(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*3; + setAcceleration(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + count += sizeof(U16)*4; + new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); + new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); + new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); + new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *) &data[count]; +#endif + setAngularVelocity( U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + break; + + case 16: + // this is a terse 8 update + this_update_precision = 8; + test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); + + setVelocity(U8_to_F32(data[3], -size, size), + U8_to_F32(data[4], -size, size), + U8_to_F32(data[5], -size, size) ); + + setAcceleration(U8_to_F32(data[6], -size, size), + U8_to_F32(data[7], -size, size), + U8_to_F32(data[8], -size, size) ); + + new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); + new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); + new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); + new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); + + setAngularVelocity( U8_to_F32(data[13], -size, size), + U8_to_F32(data[14], -size, size), + U8_to_F32(data[15], -size, size) ); + break; + } + + U8 state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); + mState = state; + break; + } + + default: + break; + + } + } + else + { + // handle the compressed case + LLUUID sound_uuid; + LLUUID owner_id; + F32 gain = 0; + U8 sound_flags = 0; + F32 cutoff = 0; + + U16 val[4]; + + U8 state; + + dp->unpackU8(state, "State"); + mState = state; + + switch(update_type) + { + case OUT_TERSE_IMPROVED: + { +#ifdef DEBUG_UPDATE_TYPE + llinfos << "CompTI:" << getID() << llendl; +#endif + U8 value; + dp->unpackU8(value, "agent"); + if (value) + { + LLVector4 collision_plane; + dp->unpackVector4(collision_plane, "Plane"); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + } + test_pos_parent = getPosition(); + dp->unpackVector3(new_pos_parent, "Pos"); + dp->unpackU16(val[VX], "VelX"); + dp->unpackU16(val[VY], "VelY"); + dp->unpackU16(val[VZ], "VelZ"); + setVelocity(U16_to_F32(val[VX], -128.f, 128.f), + U16_to_F32(val[VY], -128.f, 128.f), + U16_to_F32(val[VZ], -128.f, 128.f)); + dp->unpackU16(val[VX], "AccX"); + dp->unpackU16(val[VY], "AccY"); + dp->unpackU16(val[VZ], "AccZ"); + setAcceleration(U16_to_F32(val[VX], -64.f, 64.f), + U16_to_F32(val[VY], -64.f, 64.f), + U16_to_F32(val[VZ], -64.f, 64.f)); + + dp->unpackU16(val[VX], "ThetaX"); + dp->unpackU16(val[VY], "ThetaY"); + dp->unpackU16(val[VZ], "ThetaZ"); + dp->unpackU16(val[VS], "ThetaS"); + new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); + new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); + new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); + new_rot.mQ[VS] = U16_to_F32(val[VS], -1.f, 1.f); + dp->unpackU16(val[VX], "AccX"); + dp->unpackU16(val[VY], "AccY"); + dp->unpackU16(val[VZ], "AccZ"); + setAngularVelocity( U16_to_F32(val[VX], -64.f, 64.f), + U16_to_F32(val[VY], -64.f, 64.f), + U16_to_F32(val[VZ], -64.f, 64.f)); + } + break; + case OUT_FULL_COMPRESSED: + case OUT_FULL_CACHED: + { +#ifdef DEBUG_UPDATE_TYPE + llinfos << "CompFull:" << getID() << llendl; +#endif + mCostStale = true; + + if (isSelected()) + { + gFloaterTools->dirty(); + } + + dp->unpackU32(crc, "CRC"); + mTotalCRC = crc; + dp->unpackU8(material, "Material"); + U8 old_material = getMaterial(); + if (old_material != material) + { + setMaterial(material); + if (mDrawable.notNull()) + { + gPipeline.markMoved(mDrawable, FALSE); // undamped + } + } + dp->unpackU8(click_action, "ClickAction"); + setClickAction(click_action); + dp->unpackVector3(new_scale, "Scale"); + dp->unpackVector3(new_pos_parent, "Pos"); + LLVector3 vec; + dp->unpackVector3(vec, "Rot"); + new_rot.unpackFromVector3(vec); + setAcceleration(LLVector3::zero); + + U32 value; + dp->unpackU32(value, "SpecialCode"); + dp->setPassFlags(value); + dp->unpackUUID(owner_id, "Owner"); + + if (value & 0x80) + { + dp->unpackVector3(vec, "Omega"); + setAngularVelocity(vec); + } + + if (value & 0x20) + { + dp->unpackU32(parent_id, "ParentID"); + } + else + { + parent_id = 0; + } + + S32 sp_size; + U32 size; + if (value & 0x2) + { + sp_size = 1; + delete [] mData; + mData = new U8[1]; + dp->unpackU8(((U8*)mData)[0], "TreeData"); + } + else if (value & 0x1) + { + dp->unpackU32(size, "ScratchPadSize"); + delete [] mData; + mData = new U8[size]; + dp->unpackBinaryData((U8 *)mData, sp_size, "PartData"); + } + else + { + mData = NULL; + } + + // Setup object text + if (!mText && (value & 0x4)) + { + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); // Set to match current agni behavior. + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); + } + + if (value & 0x4) + { + std::string temp_string; + dp->unpackString(temp_string, "Text"); + LLColor4U coloru; + dp->unpackBinaryDataFixed(coloru.mV, 4, "Color"); + coloru.mV[3] = 255 - coloru.mV[3]; + mText->setColor(LLColor4(coloru)); + mText->setString(temp_string); + + setChanged(TEXTURE); + } + else if(mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + + std::string media_url; + if (value & 0x200) + { + dp->unpackString(media_url, "MediaURL"); + } + retval |= checkMediaURL(media_url); + + // + // Unpack particle system data + // + if (value & 0x8) + { + unpackParticleSource(*dp, owner_id); + } + else + { + deleteParticleSource(); + } + + // Mark all extra parameters not used + std::map<U16, ExtraParameter*>::iterator iter; + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + iter->second->in_use = FALSE; + } + + // Unpack extra params + U8 num_parameters; + dp->unpackU8(num_parameters, "num_params"); + U8 param_block[MAX_OBJECT_PARAMS_SIZE]; + for (U8 param=0; param<num_parameters; ++param) + { + U16 param_type; + S32 param_size; + dp->unpackU16(param_type, "param_type"); + dp->unpackBinaryData(param_block, param_size, "param_data"); + //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl; + LLDataPackerBinaryBuffer dp2(param_block, param_size); + unpackParameterEntry(param_type, &dp2); + } + + for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + { + if (!iter->second->in_use) + { + // Send an update message in case it was formerly in use + parameterChanged(iter->first, iter->second->data, FALSE, false); + } + } + + if (value & 0x10) + { + dp->unpackUUID(sound_uuid, "SoundUUID"); + dp->unpackF32(gain, "SoundGain"); + dp->unpackU8(sound_flags, "SoundFlags"); + dp->unpackF32(cutoff, "SoundRadius"); + } + + if (value & 0x100) + { + std::string name_value_list; + dp->unpackString(name_value_list, "NV"); + + setNameValueList(name_value_list); + } + + mTotalCRC = crc; + + setAttachedSound(sound_uuid, owner_id, gain, sound_flags); + + // only get these flags on updates from sim, not cached ones + // Preload these five flags for every object. + // Finer shades require the object to be selected, and the selection manager + // stores the extended permission info. + U32 flags; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); + // keep local flags and overwrite remote-controlled flags + mFlags = (mFlags & FLAGS_LOCAL) | flags; + + // ...new objects that should come in selected need to be added to the selected list + mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + } + break; + + default: + break; + } + } + + // + // Fix object parenting. + // + BOOL b_changed_status = FALSE; + + if (OUT_TERSE_IMPROVED != update_type) + { + // We only need to update parenting on full updates, terse updates + // don't send parenting information. + if (!cur_parentp) + { + if (parent_id == 0) + { + // No parent now, no parent in message -> do nothing + } + else + { + // No parent now, new parent in message -> attach to that parent if possible + LLUUID parent_uuid; + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + mesgsys->getSenderIP(), + mesgsys->getSenderPort()); + + LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid); + + // + // Check to see if we have the corresponding viewer object for the parent. + // + if (sent_parentp && sent_parentp->getParent() == this) + { + // Try to recover if we attempt to attach a parent to its child + llwarns << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << llendl; + this->removeChild(sent_parentp); + sent_parentp->setDrawableParent(NULL); + } + + if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead()) + { + // + // We have a viewer object for the parent, and it's not dead. + // Do the actual reparenting here. + // + + // new parent is valid + b_changed_status = TRUE; + // ...no current parent, so don't try to remove child + if (mDrawable.notNull()) + { + if (mDrawable->isDead() || !mDrawable->getVObj()) + { + llwarns << "Drawable is dead or no VObj!" << llendl; + sent_parentp->addChild(this); + } + else + { + if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 1 + { + // Bad, we got a cycle somehow. + // Kill both the parent and the child, and + // set cache misses for both of them. + llwarns << "Attempting to recover from parenting cycle!" << llendl; + llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl; + llwarns << "Adding to cache miss list" << llendl; + setParent(NULL); + sent_parentp->setParent(NULL); + getRegion()->addCacheMissFull(getLocalID()); + getRegion()->addCacheMissFull(sent_parentp->getLocalID()); + gObjectList.killObject(sent_parentp); + gObjectList.killObject(this); + return retval; + } + sent_parentp->addChild(this); + // make sure this object gets a non-damped update + if (sent_parentp->mDrawable.notNull()) + { + gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped + } + } + } + else + { + sent_parentp->addChild(this); + } + + // Show particles, icon and HUD + hideExtraDisplayItems( FALSE ); + + setChanged(MOVED | SILHOUETTE); + } + else + { + // + // No corresponding viewer object for the parent, put the various + // pieces on the orphan list. + // + + //parent_id + U32 ip = mesgsys->getSenderIP(); + U32 port = mesgsys->getSenderPort(); + + gObjectList.orphanize(this, parent_id, ip, port); + + // Hide particles, icon and HUD + hideExtraDisplayItems( TRUE ); + } + } + } + else + { + // BUG: this is a bad assumption once border crossing is alowed + if ( (parent_id == cur_parentp->mLocalID) + &&(update_type == OUT_TERSE_IMPROVED)) + { + // Parent now, same parent in message -> do nothing + + // Debugging for suspected problems with local ids. + //LLUUID parent_uuid; + //LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() ); + //if (parent_uuid != cur_parentp->getID() ) + //{ + // llerrs << "Local ID match but UUID mismatch of viewer object" << llendl; + //} + } + else + { + // Parented now, different parent in message + LLViewerObject *sent_parentp; + if (parent_id == 0) + { + // + // This object is no longer parented, we sent in a zero parent ID. + // + sent_parentp = NULL; + } + else + { + LLUUID parent_uuid; + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + gMessageSystem->getSenderIP(), + gMessageSystem->getSenderPort()); + sent_parentp = gObjectList.findObject(parent_uuid); + + if (isAvatar()) + { + // This logic is meant to handle the case where a sitting avatar has reached a new sim + // ahead of the object she was sitting on (which is common as objects are transfered through + // a slower route than agents)... + // In this case, the local id for the object will not be valid, since the viewer has not received + // a full update for the object from that sim yet, so we assume that the agent is still sitting + // where she was originally. --RN + if (!sent_parentp) + { + sent_parentp = cur_parentp; + } + } + else if (!sent_parentp) + { + // + // Switching parents, but we don't know the new parent. + // + U32 ip = mesgsys->getSenderIP(); + U32 port = mesgsys->getSenderPort(); + + // We're an orphan, flag things appropriately. + gObjectList.orphanize(this, parent_id, ip, port); + } + } + + // Reattach if possible. + if (sent_parentp && sent_parentp != cur_parentp && sent_parentp != this) + { + // New parent is valid, detach and reattach + b_changed_status = TRUE; + if (mDrawable.notNull()) + { + if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 2 + { + // Bad, we got a cycle somehow. + // Kill both the parent and the child, and + // set cache misses for both of them. + llwarns << "Attempting to recover from parenting cycle!" << llendl; + llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl; + llwarns << "Adding to cache miss list" << llendl; + setParent(NULL); + sent_parentp->setParent(NULL); + getRegion()->addCacheMissFull(getLocalID()); + getRegion()->addCacheMissFull(sent_parentp->getLocalID()); + gObjectList.killObject(sent_parentp); + gObjectList.killObject(this); + return retval; + } + // make sure this object gets a non-damped update + } + cur_parentp->removeChild(this); + sent_parentp->addChild(this); + setChanged(MOVED | SILHOUETTE); + sent_parentp->setChanged(MOVED | SILHOUETTE); + if (sent_parentp->mDrawable.notNull()) + { + gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped + } + } + else if (!sent_parentp) + { + bool remove_parent = true; + // No new parent, or the parent that we sent doesn't exist on the viewer. + LLViewerObject *parentp = (LLViewerObject *)getParent(); + if (parentp) + { + if (parentp->getRegion() != getRegion()) + { + // This is probably an object flying across a region boundary, the + // object probably ISN'T being reparented, but just got an object + // update out of order (child update before parent). + //llinfos << "Don't reparent object handoffs!" << llendl; + remove_parent = false; + } + } + + if (remove_parent) + { + b_changed_status = TRUE; + if (mDrawable.notNull()) + { + // clear parent to removeChild can put the drawable on the damped list + setDrawableParent(NULL); // LLViewerObject::processUpdateMessage 3 + } + + cur_parentp->removeChild(this); + + if (mJointInfo && !parent_id) + { + // since this object is no longer parent-relative + // we make sure we delete any joint info + delete mJointInfo; + mJointInfo = NULL; + } + + setChanged(MOVED | SILHOUETTE); + + if (mDrawable.notNull()) + { + // make sure this object gets a non-damped update + gPipeline.markMoved(mDrawable, FALSE); // undamped + } + } + } + } + } + } + + new_rot.normQuat(); + + if (sPingInterpolate) + { + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender()); + if (cdp) + { + F32 ping_delay = 0.5f * mTimeDilation * ( ((F32)cdp->getPingDelay()) * 0.001f + gFrameDTClamped); + LLVector3 diff = getVelocity() * ping_delay; + new_pos_parent += diff; + } + else + { + llwarns << "findCircuit() returned NULL; skipping interpolation" << llendl; + } + } + + ////////////////////////// + // + // Set the generic change flags... + // + // + + // WTF? If we're going to skip this message, why are we + // doing all the parenting, etc above? + U32 packet_id = mesgsys->getCurrentRecvPacketID(); + if (packet_id < mLatestRecvPacketID && + mLatestRecvPacketID - packet_id < 65536) + { + //skip application of this message, it's old + return retval; + } + + mLatestRecvPacketID = packet_id; + + // Set the change flags for scale + if (new_scale != getScale()) + { + setChanged(SCALED | SILHOUETTE); + setScale(new_scale); // Must follow setting permYouOwner() + } + + // first, let's see if the new position is actually a change + + //static S32 counter = 0; + + F32 vel_mag_sq = getVelocity().magVecSquared(); + F32 accel_mag_sq = getAcceleration().magVecSquared(); + + if ( ((b_changed_status)||(test_pos_parent != new_pos_parent)) + ||( (!isSelected()) + &&( (vel_mag_sq != 0.f) + ||(accel_mag_sq != 0.f) + ||(this_update_precision > mBestUpdatePrecision)))) + { + mBestUpdatePrecision = this_update_precision; + + LLVector3 diff = new_pos_parent - test_pos_parent ; + F32 mag_sqr = diff.magVecSquared() ; + if(llfinite(mag_sqr)) + { + setPositionParent(new_pos_parent); + } + else + { + llwarns << "Can not move the object/avatar to an infinite location!" << llendl ; + + retval |= INVALID_UPDATE ; + } + + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) + { + // we have changed the position of an attachment, so we need to clamp it + LLVOAvatar *avatar = (LLVOAvatar*)mParent; + + avatar->clampAttachmentPositions(); + } + + // If we're snapping the position by more than 0.5m, update LLViewerStats::mAgentPositionSnaps + if ( asAvatar() && asAvatar()->isSelf() && (mag_sqr > 0.25f) ) + { + LLViewerStats::getInstance()->mAgentPositionSnaps.push( diff.length() ); + } + } + + if (new_rot != mLastRot + || new_angv != old_angv) + { + if (new_rot != mLastRot) + { + mLastRot = new_rot; + setRotation(new_rot); + } + + setChanged(ROTATED | SILHOUETTE); + + resetRot(); + } + + + if ( gShowObjectUpdates ) + { + if (!((mPrimitiveCode == LL_PCODE_LEGACY_AVATAR) && (((LLVOAvatar *) this)->isSelf())) + && mRegionp) + { + LLViewerObject* object = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, mRegionp); + LLVOTextBubble* bubble = (LLVOTextBubble*) object; + + if (update_type == OUT_TERSE_IMPROVED) + { + bubble->mColor.setVec(0.f, 0.f, 1.f, 1.f); + } + else + { + bubble->mColor.setVec(1.f, 0.f, 0.f, 1.f); + } + object->setPositionGlobal(getPositionGlobal()); + gPipeline.addObject(object); + } + } + + if ((0.0f == vel_mag_sq) && + (0.0f == accel_mag_sq) && + (0.0f == getAngularVelocity().magVecSquared())) + { + mStatic = TRUE; // This object doesn't move! + } + else + { + mStatic = FALSE; + } + +// BUG: This code leads to problems during group rotate and any scale operation. +// Small discepencies between the simulator and viewer representations cause the +// selection center to creep, leading to objects moving around the wrong center. +// +// Removing this, however, means that if someone else drags an object you have +// selected, your selection center and dialog boxes will be wrong. It also means +// that higher precision information on selected objects will be ignored. +// +// I believe the group rotation problem is fixed. JNC 1.21.2002 +// + // Additionally, if any child is selected, need to update the dialogs and selection + // center. + BOOL needs_refresh = mUserSelected; + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + needs_refresh = needs_refresh || child->mUserSelected; + } + + if (needs_refresh) + { + LLSelectMgr::getInstance()->updateSelectionCenter(); + dialog_refresh_all(); + } + + + // Mark update time as approx. now, with the ping delay. + // Ping delay is off because it's not set for velocity interpolation, causing + // much jumping and hopping around... + +// U32 ping_delay = mesgsys->mCircuitInfo.getPingDelay(); + mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds(); + mLastMessageUpdateSecs = mLastInterpUpdateSecs; + if (mDrawable.notNull()) + { + // Don't clear invisibility flag on update if still orphaned! + if (mDrawable->isState(LLDrawable::FORCE_INVISIBLE) && !mOrphaned) + { +// lldebugs << "Clearing force invisible: " << mID << ":" << getPCodeString() << ":" << getPositionAgent() << llendl; + mDrawable->setState(LLDrawable::CLEAR_INVISIBLE); + } + } + + // Update special hover cursor status + bool special_hover_cursor = specialHoverCursor(); + if (old_special_hover_cursor != special_hover_cursor + && mDrawable.notNull()) + { + mDrawable->updateSpecialHoverCursor(special_hover_cursor); + } + + return retval; +} + +BOOL LLViewerObject::isActive() const +{ + return TRUE; +} + + + +BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) +{ + static LLFastTimer::DeclareTimer ftm("Viewer Object"); + LLFastTimer t(ftm); + + if (mDead) + { + // It's dead. Don't update it. + return TRUE; + } + + // CRO - don't velocity interp linked objects! + // Leviathan - but DO velocity interp joints + if (!mStatic && sVelocityInterpolate && !isSelected()) + { + // calculate dt from last update + F32 dt_raw = (F32)(time - mLastInterpUpdateSecs); + F32 dt = mTimeDilation * dt_raw; + + if (!mJointInfo) + { + applyAngularVelocity(dt); + } + + LLViewerObject *parentp = (LLViewerObject *) getParent(); + if (mJointInfo) + { + if (parentp) + { + // do parent-relative stuff + LLVector3 ang_vel = getAngularVelocity(); + F32 omega = ang_vel.magVecSquared(); + F32 angle = 0.0f; + LLQuaternion dQ; + if (omega > 0.00001f) + { + omega = sqrt(omega); + angle = omega * dt; + dQ.setQuat(angle, ang_vel); + } + LLVector3 pos = getPosition(); + + if (HJT_HINGE == mJointInfo->mJointType) + { + // hinge = uniform circular motion + LLVector3 parent_pivot = getVelocity(); + LLVector3 parent_axis = getAcceleration(); + + angle = dt * (ang_vel * mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis + dQ.setQuat(angle, mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis + LLVector3 pivot_offset = pos - mJointInfo->mPivot; // pos in pivot-frame + pivot_offset = pivot_offset * dQ; // new rotated pivot-frame pos + pos = mJointInfo->mPivot + pivot_offset; // parent-frame + LLViewerObject::setPosition(pos); + LLQuaternion Q_PC = getRotation(); + setRotation(Q_PC * dQ); + mLastInterpUpdateSecs = time; + } + else if (HJT_POINT == mJointInfo->mJointType) + // || HJT_LPOINT == mJointInfo->mJointType) + { + // point-to-point = spin about axis and uniform circular motion + // of axis about the pivot point + // + // NOTE: this interpolation scheme is not quite good enough to + // reduce the bandwidth -- needs a gravitational correction. + // Similarly for hinges with axes that deviate from vertical. + + LLQuaternion Q_PC = getRotation(); + Q_PC = Q_PC * dQ; + setRotation(Q_PC); + + LLVector3 pivot_to_child = - mJointInfo->mAxisOrAnchor; // AxisOrAnchor = anchor + pos = mJointInfo->mPivot + pivot_to_child * Q_PC; + LLViewerObject::setPosition(pos); + mLastInterpUpdateSecs = time; + } + /* else if (HJT_WHEEL == mJointInfo->mJointInfo) + { + // wheel = uniform rotation about axis, with linear + // velocity interpolation (if any) + LLVector3 parent_axis = getAcceleration(); // HACK -- accel stores the parent-axis (parent-frame) + + LLQuaternion Q_PC = getRotation(); + + angle = dt * (parent_axis * ang_vel); + dQ.setQuat(angle, parent_axis); + + Q_PC = Q_PC * dQ; + setRotation(Q_PC); + + pos = getPosition() + dt * getVelocity(); + LLViewerObject::setPosition(pos); + mLastInterpUpdateSecs = time; + }*/ + } + } + else if (isAttachment()) + { + mLastInterpUpdateSecs = time; + return TRUE; + } + else + { // Move object based on it's velocity and rotation + interpolateLinearMotion(time, dt); + } + } + + updateDrawable(FALSE); + + return TRUE; +} + + +// Move an object due to idle-time viewer side updates by iterpolating motion +void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) +{ + // linear motion + // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object + // updates represents the average velocity of the last timestep, rather than the final velocity. + // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically + // + // *TODO: should also wrap linear accel/velocity in check + // to see if object is selected, instead of explicitly + // zeroing it out + + F64 time_since_last_update = time - mLastMessageUpdateSecs; + if (time_since_last_update <= 0.0 || dt <= 0.f) + { + return; + } + + LLVector3 accel = getAcceleration(); + LLVector3 vel = getVelocity(); + + if (sMaxUpdateInterpolationTime <= 0.0) + { // Old code path ... unbounded, simple interpolation + if (!(accel.isExactlyZero() && vel.isExactlyZero())) + { + LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + + // region local + setPositionRegion(pos + getPositionRegion()); + setVelocity(vel + accel*dt); + + // for objects that are spinning but not translating, make sure to flag them as having moved + setChanged(MOVED | SILHOUETTE); + } + } + else if (!accel.isExactlyZero() || !vel.isExactlyZero()) // object is moving + { // Object is moving, and hasn't been too long since we got an update from the server + + // Calculate predicted position and velocity + LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + LLVector3 new_v = accel * dt; + + if (time_since_last_update > sPhaseOutUpdateInterpolationTime && + sPhaseOutUpdateInterpolationTime > 0.0) + { // Haven't seen a viewer update in a while, check to see if the ciruit is still active + if (mRegionp) + { // The simulator will NOT send updates if the object continues normally on the path + // predicted by the velocity and the acceleration (often gravity) sent to the viewer + // So check to see if the circuit is blocked, which means the sim is likely in a long lag + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit( mRegionp->getHost() ); + if (cdp) + { + // Find out how many seconds since last packet arrived on the circuit + F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime(); + + if (!cdp->isAlive() || // Circuit is dead or blocked + cdp->isBlocked() || // or doesn't seem to be getting any packets + (time_since_last_packet > sPhaseOutUpdateInterpolationTime)) + { + // Start to reduce motion interpolation since we haven't seen a server update in a while + F64 time_since_last_interpolation = time - mLastInterpUpdateSecs; + F64 phase_out = 1.0; + if (time_since_last_update > sMaxUpdateInterpolationTime) + { // Past the time limit, so stop the object + phase_out = 0.0; + //llinfos << "Motion phase out to zero" << llendl; + + // Kill angular motion as well. Note - not adding this due to paranoia + // about stopping rotation for llTargetOmega objects and not having it restart + // setAngularVelocity(LLVector3::zero); + } + else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs > sPhaseOutUpdateInterpolationTime) + { // Last update was already phased out a bit + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + (sMaxUpdateInterpolationTime - time_since_last_interpolation); + //llinfos << "Continuing motion phase out of " << (F32) phase_out << llendl; + } + else + { // Phase out from full value + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + (sMaxUpdateInterpolationTime - sPhaseOutUpdateInterpolationTime); + //llinfos << "Starting motion phase out of " << (F32) phase_out << llendl; + } + phase_out = llclamp(phase_out, 0.0, 1.0); + + new_pos = new_pos * ((F32) phase_out); + new_v = new_v * ((F32) phase_out); + } + } + } + } + + new_pos = new_pos + getPositionRegion(); + new_v = new_v + vel; + + + // Clamp interpolated position to minimum underground and maximum region height + LLVector3d new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos); + F32 min_height; + if (isAvatar()) + { // Make a better guess about AVs not going underground + min_height = LLWorld::getInstance()->resolveLandHeightGlobal(new_pos_global); + min_height += (0.5f * getScale().mV[VZ]); + } + else + { // This will put the object underground, but we can't tell if it will stop + // at ground level or not + min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global); + } + + new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]); + new_pos.mV[VZ] = llmin(LLWorld::getInstance()->getRegionMaxHeight(), new_pos.mV[VZ]); + + // Check to see if it's going off the region + LLVector3 temp(new_pos); + if (temp.clamp(0.f, mRegionp->getWidth())) + { // Going off this region, so see if we might end up on another region + LLVector3d old_pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion()); + new_pos_global = mRegionp->getPosGlobalFromRegion(new_pos); // Re-fetch in case it got clipped above + + // Clip the positions to known regions + LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global); + if (clip_pos_global != new_pos_global) + { // Was clipped, so this means we hit a edge where there is no region to enter + + //llinfos << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global) + // << " from " << new_pos << llendl; + new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global); + + // Stop motion and get server update for bouncing on the edge + new_v.clear(); + setAcceleration(LLVector3::zero); + } + else + { // Let predicted movement cross into another region + //llinfos << "Predicting region crossing to " << new_pos << llendl; + } + } + + // Set new position and velocity + setPositionRegion(new_pos); + setVelocity(new_v); + + // for objects that are spinning but not translating, make sure to flag them as having moved + setChanged(MOVED | SILHOUETTE); + } + + // Update the last time we did anything + mLastInterpUpdateSecs = time; +} + + + +BOOL LLViewerObject::setData(const U8 *datap, const U32 data_size) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + delete [] mData; + + if (datap) + { + mData = new U8[data_size]; + if (!mData) + { + return FALSE; + } + memcpy(mData, datap, data_size); /* Flawfinder: ignore */ + } + return TRUE; +} + +// delete an item in the inventory, but don't tell the server. This is +// used internally by remove, update, and savescript. +// This will only delete the first item with an item_id in the list +void LLViewerObject::deleteInventoryItem(const LLUUID& item_id) +{ + if(mInventory) + { + LLInventoryObject::object_list_t::iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = mInventory->end(); + for( ; it != end; ++it ) + { + if((*it)->getUUID() == item_id) + { + // This is safe only because we return immediatly. + mInventory->erase(it); // will deref and delete it + return; + } + } + doInventoryCallback(); + } +} + +void LLViewerObject::doUpdateInventory( + LLPointer<LLViewerInventoryItem>& item, + U8 key, + bool is_new) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + LLViewerInventoryItem* old_item = NULL; + if(TASK_INVENTORY_ITEM_KEY == key) + { + old_item = (LLViewerInventoryItem*)getInventoryObject(item->getUUID()); + } + else if(TASK_INVENTORY_ASSET_KEY == key) + { + old_item = getInventoryItemByAsset(item->getAssetUUID()); + } + LLUUID item_id; + LLUUID new_owner; + LLUUID new_group; + BOOL group_owned = FALSE; + if(old_item) + { + item_id = old_item->getUUID(); + new_owner = old_item->getPermissions().getOwner(); + new_group = old_item->getPermissions().getGroup(); + group_owned = old_item->getPermissions().isGroupOwned(); + old_item = NULL; + } + else + { + item_id = item->getUUID(); + } + if(!is_new && mInventory) + { + // Attempt to update the local inventory. If we can get the + // object perm, we have perfect visibility, so we want the + // serial number to match. Otherwise, take our best guess and + // make sure that the serial number does not match. + deleteInventoryItem(item_id); + LLPermissions perm(item->getPermissions()); + LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this); + bool is_atomic = ((S32)LLAssetType::AT_OBJECT == item->getType()) ? false : true; + if(obj_perm) + { + perm.setOwnerAndGroup(LLUUID::null, obj_perm->getOwner(), obj_perm->getGroup(), is_atomic); + } + else + { + if(group_owned) + { + perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic); + } + else if(!new_owner.isNull()) + { + // The object used to be in inventory, so we can + // assume the owner and group will match what they are + // there. + perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic); + } + // *FIX: can make an even better guess by using the mPermGroup flags + else if(permYouOwner()) + { + // best guess. + perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic); + --mInventorySerialNum; + } + else + { + // dummy it up. + perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic); + --mInventorySerialNum; + } + } + LLViewerInventoryItem* oldItem = item; + LLViewerInventoryItem* new_item = new LLViewerInventoryItem(oldItem); + new_item->setPermissions(perm); + mInventory->push_front(new_item); + doInventoryCallback(); + ++mInventorySerialNum; + } +} + +// save a script, which involves removing the old one, and rezzing +// in the new one. This method should be called with the asset id +// of the new and old script AFTER the bytecode has been saved. +void LLViewerObject::saveScript( + const LLViewerInventoryItem* item, + BOOL active, + bool is_new) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + /* + * XXXPAM Investigate not making this copy. Seems unecessary, but I'm unsure about the + * interaction with doUpdateInventory() called below. + */ + lldebugs << "LLViewerObject::saveScript() " << item->getUUID() << " " << item->getAssetUUID() << llendl; + LLPointer<LLViewerInventoryItem> task_item = + new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), + item->getAssetUUID(), item->getType(), + item->getInventoryType(), + item->getName(), item->getDescription(), + item->getSaleInfo(), item->getFlags(), + item->getCreationDate()); + task_item->setTransactionID(item->getTransactionID()); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RezScript); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + msg->nextBlockFast(_PREHASH_UpdateBlock); + msg->addU32Fast(_PREHASH_ObjectLocalID, (mLocalID)); + U8 enabled = active; + msg->addBOOLFast(_PREHASH_Enabled, enabled); + msg->nextBlockFast(_PREHASH_InventoryBlock); + task_item->packMessage(msg); + msg->sendReliable(mRegionp->getHost()); + + // do the internal logic + doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, is_new); +} + +void LLViewerObject::moveInventory(const LLUUID& folder_id, + const LLUUID& item_id) +{ + lldebugs << "LLViewerObject::moveInventory " << item_id << llendl; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MoveTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_FolderID, folder_id); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + msg->sendReliable(mRegionp->getHost()); + + LLInventoryObject* inv_obj = getInventoryObject(item_id); + if(inv_obj) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_obj; + if(!item->getPermissions().allowCopyBy(gAgent.getID())) + { + deleteInventoryItem(item_id); + ++mInventorySerialNum; + } + } +} + +void LLViewerObject::dirtyInventory() +{ + // If there aren't any LLVOInventoryListeners, we won't be + // able to update our mInventory when it comes back from the + // simulator, so we should not clear the inventory either. + if(mInventory && !mInventoryCallbacks.empty()) + { + mInventory->clear(); // will deref and delete entries + delete mInventory; + mInventory = NULL; + mInventoryDirty = TRUE; + } +} + +void LLViewerObject::registerInventoryListener(LLVOInventoryListener* listener, void* user_data) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + LLInventoryCallbackInfo* info = new LLInventoryCallbackInfo; + info->mListener = listener; + info->mInventoryData = user_data; + mInventoryCallbacks.push_front(info); +} + +void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener) +{ + if (listener == NULL) + return; + for (callback_list_t::iterator iter = mInventoryCallbacks.begin(); + iter != mInventoryCallbacks.end(); ) + { + callback_list_t::iterator curiter = iter++; + LLInventoryCallbackInfo* info = *curiter; + if (info->mListener == listener) + { + delete info; + mInventoryCallbacks.erase(curiter); + break; + } + } +} + +void LLViewerObject::clearInventoryListeners() +{ + for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer()); + mInventoryCallbacks.clear(); +} + +void LLViewerObject::requestInventory() +{ + mInventoryDirty = FALSE; + if(mInventory) + { + //mInventory->clear() // will deref and delete it + //delete mInventory; + //mInventory = NULL; + doInventoryCallback(); + } + // throw away duplicate requests + else + { + fetchInventoryFromServer(); + } +} + +void LLViewerObject::fetchInventoryFromServer() +{ + if (!mInventoryPending) + { + delete mInventory; + mInventory = NULL; + mInventoryDirty = FALSE; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RequestTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->sendReliable(mRegionp->getHost()); + + // this will get reset by dirtyInventory or doInventoryCallback + mInventoryPending = TRUE; + } +} + +struct LLFilenameAndTask +{ + LLUUID mTaskID; + std::string mFilename; +#ifdef _DEBUG + static S32 sCount; + LLFilenameAndTask() + { + ++sCount; + lldebugs << "Constructing LLFilenameAndTask: " << sCount << llendl; + } + ~LLFilenameAndTask() + { + --sCount; + lldebugs << "Destroying LLFilenameAndTask: " << sCount << llendl; + } +private: + LLFilenameAndTask(const LLFilenameAndTask& rhs); + const LLFilenameAndTask& operator=(const LLFilenameAndTask& rhs) const; +#endif +}; + +#ifdef _DEBUG +S32 LLFilenameAndTask::sCount = 0; +#endif + +// static +void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + LLUUID task_id; + msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id); + LLViewerObject* object = gObjectList.findObject(task_id); + if(!object) + { + llwarns << "LLViewerObject::processTaskInv object " + << task_id << " does not exist." << llendl; + return; + } + + msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum); + LLFilenameAndTask* ft = new LLFilenameAndTask; + ft->mTaskID = task_id; + + std::string unclean_filename; + msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); + ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); + + if(ft->mFilename.empty()) + { + lldebugs << "Task has no inventory" << llendl; + // mock up some inventory to make a drop target. + if(object->mInventory) + { + object->mInventory->clear(); // will deref and delete it + } + else + { + object->mInventory = new LLInventoryObject::object_list_t(); + } + LLPointer<LLInventoryObject> obj; + obj = new LLInventoryObject(object->mID, LLUUID::null, + LLAssetType::AT_CATEGORY, + LLTrans::getString("ViewerObjectContents").c_str()); + object->mInventory->push_front(obj); + object->doInventoryCallback(); + delete ft; + return; + } + gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), + ft->mFilename, LL_PATH_CACHE, + object->mRegionp->getHost(), + TRUE, + &LLViewerObject::processTaskInvFile, + (void**)ft, + LLXferManager::HIGH_PRIORITY); +} + +void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) +{ + LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data; + LLViewerObject* object = NULL; + if(ft && (0 == error_code) && + (object = gObjectList.findObject(ft->mTaskID))) + { + object->loadTaskInvFile(ft->mFilename); + } + else + { + // This Occurs When to requests were made, and the first one + // has already handled it. + lldebugs << "Problem loading task inventory. Return code: " + << error_code << llendl; + } + delete ft; +} + +void LLViewerObject::loadTaskInvFile(const std::string& filename) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename); + llifstream ifs(filename_and_local_path); + if(ifs.good()) + { + char buffer[MAX_STRING]; /* Flawfinder: ignore */ + // *NOTE: This buffer size is hard coded into scanf() below. + char keyword[MAX_STRING]; /* Flawfinder: ignore */ + if(mInventory) + { + mInventory->clear(); // will deref and delete it + } + else + { + mInventory = new LLInventoryObject::object_list_t; + } + while(ifs.good()) + { + ifs.getline(buffer, MAX_STRING); + sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */ + if(0 == strcmp("inv_item", keyword)) + { + LLPointer<LLInventoryObject> inv = new LLViewerInventoryItem; + inv->importLegacyStream(ifs); + mInventory->push_front(inv); + } + else if(0 == strcmp("inv_object", keyword)) + { + LLPointer<LLInventoryObject> inv = new LLInventoryObject; + inv->importLegacyStream(ifs); + inv->rename(LLTrans::getString("ViewerObjectContents").c_str()); + mInventory->push_front(inv); + } + else + { + llwarns << "Unknown token in inventory file '" + << keyword << "'" << llendl; + } + } + ifs.close(); + LLFile::remove(filename_and_local_path); + } + else + { + llwarns << "unable to load task inventory: " << filename_and_local_path + << llendl; + } + doInventoryCallback(); +} + +void LLViewerObject::doInventoryCallback() +{ + for (callback_list_t::iterator iter = mInventoryCallbacks.begin(); + iter != mInventoryCallbacks.end(); ) + { + callback_list_t::iterator curiter = iter++; + LLInventoryCallbackInfo* info = *curiter; + if (info->mListener != NULL) + { + info->mListener->inventoryChanged(this, + mInventory, + mInventorySerialNum, + info->mInventoryData); + } + else + { + llinfos << "LLViewerObject::doInventoryCallback() deleting bad listener entry." << llendl; + delete info; + mInventoryCallbacks.erase(curiter); + } + } + mInventoryPending = FALSE; +} + +void LLViewerObject::removeInventory(const LLUUID& item_id) +{ + // close any associated floater properties + LLFloaterReg::hideInstance("properties", item_id); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + msg->sendReliable(mRegionp->getHost()); + deleteInventoryItem(item_id); + ++mInventorySerialNum; +} + +void LLViewerObject::updateInventory( + LLViewerInventoryItem* item, + U8 key, + bool is_new) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + // This slices the object into what we're concerned about on the + // viewer. The simulator will take the permissions and transfer + // ownership. + LLPointer<LLViewerInventoryItem> task_item = + new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), + item->getAssetUUID(), item->getType(), + item->getInventoryType(), + item->getName(), item->getDescription(), + item->getSaleInfo(), + item->getFlags(), + item->getCreationDate()); + task_item->setTransactionID(item->getTransactionID()); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateTaskInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_UpdateData); + msg->addU32Fast(_PREHASH_LocalID, mLocalID); + msg->addU8Fast(_PREHASH_Key, key); + msg->nextBlockFast(_PREHASH_InventoryData); + task_item->packMessage(msg); + msg->sendReliable(mRegionp->getHost()); + + // do the internal logic + doUpdateInventory(task_item, key, is_new); +} + +void LLViewerObject::updateInventoryLocal(LLInventoryItem* item, U8 key) +{ + LLPointer<LLViewerInventoryItem> task_item = + new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), + item->getAssetUUID(), item->getType(), + item->getInventoryType(), + item->getName(), item->getDescription(), + item->getSaleInfo(), item->getFlags(), + item->getCreationDate()); + + // do the internal logic + const bool is_new = false; + doUpdateInventory(task_item, key, is_new); +} + +LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id) +{ + LLInventoryObject* rv = NULL; + if(mInventory) + { + LLInventoryObject::object_list_t::iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = mInventory->end(); + for ( ; it != end; ++it) + { + if((*it)->getUUID() == item_id) + { + rv = *it; + break; + } + } + } + return rv; +} + +void LLViewerObject::getInventoryContents(LLInventoryObject::object_list_t& objects) +{ + if(mInventory) + { + LLInventoryObject::object_list_t::iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = mInventory->end(); + for( ; it != end; ++it) + { + if ((*it)->getType() != LLAssetType::AT_CATEGORY) + { + objects.push_back(*it); + } + } + } +} + +LLInventoryObject* LLViewerObject::getInventoryRoot() +{ + if (!mInventory || !mInventory->size()) + { + return NULL; + } + return mInventory->back(); +} + +LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& asset_id) +{ + if (mInventoryDirty) + llwarns << "Peforming inventory lookup for object " << mID << " that has dirty inventory!" << llendl; + + LLViewerInventoryItem* rv = NULL; + if(mInventory) + { + LLViewerInventoryItem* item = NULL; + + LLInventoryObject::object_list_t::iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = mInventory->end(); + for( ; it != end; ++it) + { + LLInventoryObject* obj = *it; + if(obj->getType() != LLAssetType::AT_CATEGORY) + { + // *FIX: gank-ass down cast! + item = (LLViewerInventoryItem*)obj; + if(item->getAssetUUID() == asset_id) + { + rv = item; + break; + } + } + } + } + return rv; +} + +void LLViewerObject::updateViewerInventoryAsset( + const LLViewerInventoryItem* item, + const LLUUID& new_asset) +{ + LLPointer<LLViewerInventoryItem> task_item = + new LLViewerInventoryItem(item); + task_item->setAssetUUID(new_asset); + + // do the internal logic + doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, false); +} + +void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) +{ + if (getVolume()) + { //volumes calculate pixel area and angle per face + return; + } + + LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); + LLVector3 pos_agent = getRenderPosition(); + + F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX]; + F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY]; + F32 dz = viewer_pos_agent.mV[VZ] - pos_agent.mV[VZ]; + + F32 max_scale = getMaxScale(); + F32 mid_scale = getMidScale(); + F32 min_scale = getMinScale(); + + // IW: estimate - when close to large objects, computing range based on distance from center is no good + // to try to get a min distance from face, subtract min_scale/2 from the range. + // This means we'll load too much detail sometimes, but that's better than not enough + // I don't think there's a better way to do this without calculating distance per-poly + F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2; + + LLViewerCamera* camera = LLViewerCamera::getInstance(); + if (range < 0.001f || isHUDAttachment()) // range == zero + { + mAppAngle = 180.f; + mPixelArea = (F32)camera->getScreenPixelArea(); + } + else + { + mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG; + + F32 pixels_per_meter = camera->getPixelMeterRatio() / range; + + mPixelArea = (pixels_per_meter * max_scale) * (pixels_per_meter * mid_scale); + if (mPixelArea > camera->getScreenPixelArea()) + { + mAppAngle = 180.f; + mPixelArea = (F32)camera->getScreenPixelArea(); + } + } +} + +BOOL LLViewerObject::updateLOD() +{ + return FALSE; +} + +BOOL LLViewerObject::updateGeometry(LLDrawable *drawable) +{ + return TRUE; +} + +void LLViewerObject::updateGL() +{ + +} + +void LLViewerObject::updateFaceSize(S32 idx) +{ + +} + +LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline) +{ + return NULL; +} + +void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped) +{ + LLPrimitive::setScale(scale); + if (mDrawable.notNull()) + { + //encompass completely sheared objects by taking + //the most extreme point possible (<1,1,0.5>) + mDrawable->setRadius(LLVector3(1,1,0.5f).scaleVec(scale).magVec()); + updateDrawable(damped); + } + + if( (LL_PCODE_VOLUME == getPCode()) && !isDead() ) + { + if (permYouOwner() || (scale.magVecSquared() > (7.5f * 7.5f)) ) + { + if (!mOnMap) + { + llassert_always(LLWorld::getInstance()->getRegionFromHandle(getRegion()->getHandle())); + + gObjectList.addToMap(this); + mOnMap = TRUE; + } + } + else + { + if (mOnMap) + { + gObjectList.removeFromMap(this); + mOnMap = FALSE; + } + } + } +} + +void LLViewerObject::setObjectCost(F32 cost) +{ + mObjectCost = cost; + mCostStale = false; + + if (isSelected()) + { + gFloaterTools->dirty(); + } +} + +void LLViewerObject::setLinksetCost(F32 cost) +{ + mLinksetCost = cost; + mCostStale = false; + + if (isSelected()) + { + gFloaterTools->dirty(); + } +} + +void LLViewerObject::setPhysicsCost(F32 cost) +{ + mPhysicsCost = cost; + mCostStale = false; + + if (isSelected()) + { + gFloaterTools->dirty(); + } +} + +void LLViewerObject::setLinksetPhysicsCost(F32 cost) +{ + mLinksetPhysicsCost = cost; + mCostStale = false; + + if (isSelected()) + { + gFloaterTools->dirty(); + } +} + + +F32 LLViewerObject::getObjectCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mObjectCost; +} + +F32 LLViewerObject::getLinksetCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mLinksetCost; +} + +F32 LLViewerObject::getPhysicsCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mPhysicsCost; +} + +F32 LLViewerObject::getLinksetPhysicsCost() +{ + if (mCostStale) + { + gObjectList.updateObjectCost(this); + } + + return mLinksetPhysicsCost; +} + +F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes) +{ + return 0.f; +} + +U32 LLViewerObject::getTriangleCount() +{ + return 0; +} + +U32 LLViewerObject::getHighLODTriangleCount() +{ + return 0; +} + +void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) +{ + LLVector4a center; + center.load3(getRenderPosition().mV); + LLVector4a size; + size.load3(getScale().mV); + newMin.setSub(center, size); + newMax.setAdd(center, size); + + mDrawable->setPositionGroup(center); +} + +F32 LLViewerObject::getBinRadius() +{ + if (mDrawable.notNull()) + { + const LLVector4a* ext = mDrawable->getSpatialExtents(); + LLVector4a diff; + diff.setSub(ext[1], ext[0]); + return diff.getLength3().getF32(); + } + + return getScale().magVec(); +} + +F32 LLViewerObject::getMaxScale() const +{ + return llmax(getScale().mV[VX],getScale().mV[VY], getScale().mV[VZ]); +} + +F32 LLViewerObject::getMinScale() const +{ + return llmin(getScale().mV[0],getScale().mV[1],getScale().mV[2]); +} + +F32 LLViewerObject::getMidScale() const +{ + if (getScale().mV[VX] < getScale().mV[VY]) + { + if (getScale().mV[VY] < getScale().mV[VZ]) + { + return getScale().mV[VY]; + } + else if (getScale().mV[VX] < getScale().mV[VZ]) + { + return getScale().mV[VZ]; + } + else + { + return getScale().mV[VX]; + } + } + else if (getScale().mV[VX] < getScale().mV[VZ]) + { + return getScale().mV[VX]; + } + else if (getScale().mV[VY] < getScale().mV[VZ]) + { + return getScale().mV[VZ]; + } + else + { + return getScale().mV[VY]; + } +} + + +void LLViewerObject::updateTextures() +{ +} + +void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) +{ + if (isDead()) + { + return; + } + + S32 i; + S32 tex_count = getNumTEs(); + for (i = 0; i < tex_count; i++) + { + getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); + } + + if (isSculpted() && !isMesh()) + { + LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + LLUUID sculpt_id = sculpt_params->getSculptTexture(); + LLViewerTextureManager::getFetchedTexture(sculpt_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); + } + + if (boost_children) + { + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->boostTexturePriority(); + } + } +} + + +void LLViewerObject::setLineWidthForWindowSize(S32 window_width) +{ + if (window_width < 700) + { + LLUI::setLineWidth(2.0f); + } + else if (window_width < 1100) + { + LLUI::setLineWidth(3.0f); + } + else if (window_width < 2000) + { + LLUI::setLineWidth(4.0f); + } + else + { + // _damn_, what a nice monitor! + LLUI::setLineWidth(5.0f); + } +} + +void LLViewerObject::increaseArrowLength() +{ +/* ??? + if (mAxisArrowLength == 50) + { + mAxisArrowLength = 100; + } + else + { + mAxisArrowLength = 150; + } +*/ +} + + +void LLViewerObject::decreaseArrowLength() +{ +/* ??? + if (mAxisArrowLength == 150) + { + mAxisArrowLength = 100; + } + else + { + mAxisArrowLength = 50; + } +*/ +} + +// Culled from newsim LLTask::addNVPair +void LLViewerObject::addNVPair(const std::string& data) +{ + // cout << "LLViewerObject::addNVPair() with ---" << data << "---" << endl; + LLNameValue *nv = new LLNameValue(data.c_str()); + +// char splat[MAX_STRING]; +// temp->printNameValue(splat); +// llinfos << "addNVPair " << splat << llendl; + + name_value_map_t::iterator iter = mNameValuePairs.find(nv->mName); + if (iter != mNameValuePairs.end()) + { + LLNameValue* foundnv = iter->second; + if (foundnv->mClass != NVC_READ_ONLY) + { + delete foundnv; + mNameValuePairs.erase(iter); + } + else + { + delete nv; +// llinfos << "Trying to write to Read Only NVPair " << temp->mName << " in addNVPair()" << llendl; + return; + } + } + mNameValuePairs[nv->mName] = nv; +} + +BOOL LLViewerObject::removeNVPair(const std::string& name) +{ + char* canonical_name = gNVNameTable.addString(name); + + lldebugs << "LLViewerObject::removeNVPair(): " << name << llendl; + + name_value_map_t::iterator iter = mNameValuePairs.find(canonical_name); + if (iter != mNameValuePairs.end()) + { + if( mRegionp ) + { + LLNameValue* nv = iter->second; +/* + std::string buffer = nv->printNameValue(); + gMessageSystem->newMessageFast(_PREHASH_RemoveNameValuePair); + gMessageSystem->nextBlockFast(_PREHASH_TaskData); + gMessageSystem->addUUIDFast(_PREHASH_ID, mID); + + gMessageSystem->nextBlockFast(_PREHASH_NameValueData); + gMessageSystem->addStringFast(_PREHASH_NVPair, buffer); + + gMessageSystem->sendReliable( mRegionp->getHost() ); +*/ + // Remove the NV pair from the local list. + delete nv; + mNameValuePairs.erase(iter); + return TRUE; + } + else + { + lldebugs << "removeNVPair - No region for object" << llendl; + } + } + return FALSE; +} + + +LLNameValue *LLViewerObject::getNVPair(const std::string& name) const +{ + char *canonical_name; + + canonical_name = gNVNameTable.addString(name); + + // If you access a map with a name that isn't in it, it will add the name and a null pointer. + // So first check if the data is in the map. + name_value_map_t::const_iterator iter = mNameValuePairs.find(canonical_name); + if (iter != mNameValuePairs.end()) + { + return iter->second; + } + else + { + return NULL; + } +} + +void LLViewerObject::updatePositionCaches() const +{ + if(mRegionp) + { + if (!isRoot()) + { + mPositionRegion = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation(); + mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); + } + else + { + mPositionRegion = getPosition(); + mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); + } + } +} + +const LLVector3d LLViewerObject::getPositionGlobal() const +{ + if(mRegionp) + { + LLVector3d position_global = mRegionp->getPosGlobalFromRegion(getPositionRegion()); + + if (isAttachment()) + { + position_global = gAgent.getPosGlobalFromAgent(getRenderPosition()); + } + return position_global; + } + else + { + LLVector3d position_global(getPosition()); + return position_global; + } +} + +const LLVector3 &LLViewerObject::getPositionAgent() const +{ + if (mRegionp) + { + if (mDrawable.notNull() && (!mDrawable->isRoot() && getParent())) + { + // Don't return cached position if you have a parent, recalc (until all dirtying is done correctly. + LLVector3 position_region; + position_region = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation(); + mPositionAgent = mRegionp->getPosAgentFromRegion(position_region); + } + else + { + mPositionAgent = mRegionp->getPosAgentFromRegion(getPosition()); + } + } + return mPositionAgent; +} + +const LLVector3 &LLViewerObject::getPositionRegion() const +{ + if (!isRoot()) + { + LLViewerObject *parent = (LLViewerObject *)getParent(); + mPositionRegion = parent->getPositionRegion() + (getPosition() * parent->getRotation()); + } + else + { + mPositionRegion = getPosition(); + } + + return mPositionRegion; +} + +const LLVector3 LLViewerObject::getPositionEdit() const +{ + if (isRootEdit()) + { + return getPosition(); + } + else + { + LLViewerObject *parent = (LLViewerObject *)getParent(); + LLVector3 position_edit = parent->getPositionEdit() + getPosition() * parent->getRotationEdit(); + return position_edit; + } +} + +const LLVector3 LLViewerObject::getRenderPosition() const +{ + if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) + { + LLVOAvatar* avatar = getAvatar(); + if (avatar) + { + return avatar->getPositionAgent(); + } + } + + if (mDrawable.isNull() || mDrawable->getGeneration() < 0) + { + return getPositionAgent(); + } + else + { + return mDrawable->getPositionAgent(); + } +} + +const LLVector3 LLViewerObject::getPivotPositionAgent() const +{ + return getRenderPosition(); +} + +const LLQuaternion LLViewerObject::getRenderRotation() const +{ + LLQuaternion ret; + if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) + { + return ret; + } + + if (mDrawable.isNull() || mDrawable->isStatic()) + { + ret = getRotationEdit(); + } + else + { + if (!mDrawable->isRoot()) + { + ret = getRotation() * LLQuaternion(mDrawable->getParent()->getWorldMatrix()); + } + else + { + ret = LLQuaternion(mDrawable->getWorldMatrix()); + } + } + + return ret; +} + +const LLMatrix4 LLViewerObject::getRenderMatrix() const +{ + return mDrawable->getWorldMatrix(); +} + +const LLQuaternion LLViewerObject::getRotationRegion() const +{ + LLQuaternion global_rotation = getRotation(); + if (!((LLXform *)this)->isRoot()) + { + global_rotation = global_rotation * getParent()->getRotation(); + } + return global_rotation; +} + +const LLQuaternion LLViewerObject::getRotationEdit() const +{ + LLQuaternion global_rotation = getRotation(); + if (!((LLXform *)this)->isRootEdit()) + { + global_rotation = global_rotation * getParent()->getRotation(); + } + return global_rotation; +} + +void LLViewerObject::setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped ) +{ + if (isAttachment()) + { + LLVector3 new_pos = mRegionp->getPosRegionFromGlobal(pos_global); + if (isRootEdit()) + { + new_pos -= mDrawable->mXform.getParent()->getWorldPosition(); + LLQuaternion world_rotation = mDrawable->mXform.getParent()->getWorldRotation(); + new_pos = new_pos * ~world_rotation; + } + else + { + LLViewerObject* parentp = (LLViewerObject*)getParent(); + new_pos -= parentp->getPositionAgent(); + new_pos = new_pos * ~parentp->getRotationRegion(); + } + LLViewerObject::setPosition(new_pos); + + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) + { + // we have changed the position of an attachment, so we need to clamp it + LLVOAvatar *avatar = (LLVOAvatar*)mParent; + + avatar->clampAttachmentPositions(); + } + } + else + { + if( isRoot() ) + { + setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global)); + } + else + { + // the relative position with the parent is not constant + LLViewerObject* parent = (LLViewerObject *)getParent(); + //RN: this assumes we are only calling this function from the edit tools + gPipeline.updateMoveNormalAsync(parent->mDrawable); + + LLVector3 pos_local = mRegionp->getPosRegionFromGlobal(pos_global) - parent->getPositionRegion(); + pos_local = pos_local * ~parent->getRotationRegion(); + LLViewerObject::setPosition( pos_local ); + } + } + //RN: assumes we always want to snap the object when calling this function + gPipeline.updateMoveNormalAsync(mDrawable); +} + +void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped) +{ + if (getPosition() != pos) + { + setChanged(TRANSLATED | SILHOUETTE); + } + + LLXform::setPosition(pos); + updateDrawable(damped); + if (isRoot()) + { + // position caches need to be up to date on root objects + updatePositionCaches(); + } +} + +void LLViewerObject::setPositionGlobal(const LLVector3d &pos_global, BOOL damped) +{ + if (isAttachment()) + { + if (isRootEdit()) + { + LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global); + newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition(); + + LLQuaternion invWorldRotation = mDrawable->mXform.getParent()->getWorldRotation(); + invWorldRotation.transQuat(); + + newPos = newPos * invWorldRotation; + LLViewerObject::setPosition(newPos); + } + else + { + // assumes parent is root editable (root of attachment) + LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global); + newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition(); + LLVector3 delta_pos = newPos - getPosition(); + + LLQuaternion invRotation = mDrawable->getRotation(); + invRotation.transQuat(); + + delta_pos = delta_pos * invRotation; + + // *FIX: is this right? Shouldn't we be calling the + // LLViewerObject version of setPosition? + LLVector3 old_pos = mDrawable->mXform.getParent()->getPosition(); + mDrawable->mXform.getParent()->setPosition(old_pos + delta_pos); + setChanged(TRANSLATED | SILHOUETTE); + } + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) + { + // we have changed the position of an attachment, so we need to clamp it + LLVOAvatar *avatar = (LLVOAvatar*)mParent; + + avatar->clampAttachmentPositions(); + } + } + else + { + if (isRoot()) + { + setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global)); + } + else + { + // the relative position with the parent is constant, but the parent's position needs to be changed + LLVector3d position_offset; + position_offset.setVec(getPosition()*getParent()->getRotation()); + LLVector3d new_pos_global = pos_global - position_offset; + ((LLViewerObject *)getParent())->setPositionGlobal(new_pos_global); + } + } + updateDrawable(damped); +} + + +void LLViewerObject::setPositionParent(const LLVector3 &pos_parent, BOOL damped) +{ + // Set position relative to parent, if no parent, relative to region + if (!isRoot()) + { + LLViewerObject::setPosition(pos_parent, damped); + //updateDrawable(damped); + } + else + { + setPositionRegion(pos_parent, damped); + } +} + +void LLViewerObject::setPositionRegion(const LLVector3 &pos_region, BOOL damped) +{ + if (!isRootEdit()) + { + LLViewerObject* parent = (LLViewerObject*) getParent(); + LLViewerObject::setPosition((pos_region-parent->getPositionRegion())*~parent->getRotationRegion()); + } + else + { + LLViewerObject::setPosition(pos_region); + mPositionRegion = pos_region; + mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); + } +} + +void LLViewerObject::setPositionAgent(const LLVector3 &pos_agent, BOOL damped) +{ + LLVector3 pos_region = getRegion()->getPosRegionFromAgent(pos_agent); + setPositionRegion(pos_region, damped); +} + +// identical to setPositionRegion() except it checks for child-joints +// and doesn't also move the joint-parent +// TODO -- implement similar intelligence for joint-parents toward +// their joint-children +void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped) +{ + if (!isRootEdit()) + { + // the relative position with the parent is constant, but the parent's position needs to be changed + LLVector3 position_offset = getPosition() * getParent()->getRotation(); + + ((LLViewerObject *)getParent())->setPositionEdit(pos_edit - position_offset); + updateDrawable(damped); + } + else if (isJointChild()) + { + // compute new parent-relative position + LLViewerObject *parent = (LLViewerObject *) getParent(); + LLQuaternion inv_parent_rot = parent->getRotation(); + inv_parent_rot.transQuat(); + LLVector3 pos_parent = (pos_edit - parent->getPositionRegion()) * inv_parent_rot; + LLViewerObject::setPosition(pos_parent, damped); + } + else + { + LLViewerObject::setPosition(pos_edit, damped); + mPositionRegion = pos_edit; + mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); + } +} + + +LLViewerObject* LLViewerObject::getRootEdit() const +{ + const LLViewerObject* root = this; + while (root->mParent + && !(root->mJointInfo + || ((LLViewerObject*)root->mParent)->isAvatar()) ) + { + root = (LLViewerObject*)root->mParent; + } + return (LLViewerObject*)root; +} + + +BOOL LLViewerObject::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face, + BOOL pick_transparent, + S32* face_hit, + LLVector3* intersection, + LLVector2* tex_coord, + LLVector3* normal, + LLVector3* bi_normal) +{ + return false; +} + +BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end) +{ + if (mDrawable.isNull() || mDrawable->isDead()) + { + return FALSE; + } + + const LLVector4a* ext = mDrawable->getSpatialExtents(); + + //VECTORIZE THIS + LLVector4a center; + center.setAdd(ext[1], ext[0]); + center.mul(0.5f); + LLVector4a size; + size.setSub(ext[1], ext[0]); + size.mul(0.5f); + + LLVector4a starta, enda; + starta.load3(start.mV); + enda.load3(end.mV); + + return LLLineSegmentBoxIntersect(starta, enda, center, size); +} + +U8 LLViewerObject::getMediaType() const +{ + if (mMedia) + { + return mMedia->mMediaType; + } + else + { + return LLViewerObject::MEDIA_NONE; + } +} + +void LLViewerObject::setMediaType(U8 media_type) +{ + if (!mMedia) + { + // TODO what if we don't have a media pointer? + } + else if (mMedia->mMediaType != media_type) + { + mMedia->mMediaType = media_type; + + // TODO: update materials with new image + } +} + +std::string LLViewerObject::getMediaURL() const +{ + if (mMedia) + { + return mMedia->mMediaURL; + } + else + { + return std::string(); + } +} + +void LLViewerObject::setMediaURL(const std::string& media_url) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + if (!mMedia) + { + mMedia = new LLViewerObjectMedia; + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + + // TODO: update materials with new image + } + else if (mMedia->mMediaURL != media_url) + { + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + + // TODO: update materials with new image + } +} + +BOOL LLViewerObject::getMediaPassedWhitelist() const +{ + if (mMedia) + { + return mMedia->mPassedWhitelist; + } + else + { + return FALSE; + } +} + +void LLViewerObject::setMediaPassedWhitelist(BOOL passed) +{ + if (mMedia) + { + mMedia->mPassedWhitelist = passed; + } +} + +BOOL LLViewerObject::setMaterial(const U8 material) +{ + BOOL res = LLPrimitive::setMaterial(material); + if (res) + { + setChanged(TEXTURE); + } + return res; +} + +void LLViewerObject::setNumTEs(const U8 num_tes) +{ + LLMemType mt(LLMemType::MTYPE_OBJECT); + + U32 i; + if (num_tes != getNumTEs()) + { + if (num_tes) + { + LLPointer<LLViewerTexture> *new_images; + new_images = new LLPointer<LLViewerTexture>[num_tes]; + for (i = 0; i < num_tes; i++) + { + if (i < getNumTEs()) + { + new_images[i] = mTEImages[i]; + } + else if (getNumTEs()) + { + new_images[i] = mTEImages[getNumTEs()-1]; + } + else + { + new_images[i] = NULL; + } + } + + deleteTEImages(); + + mTEImages = new_images; + } + else + { + deleteTEImages(); + } + LLPrimitive::setNumTEs(num_tes); + setChanged(TEXTURE); + + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + } + } +} + +void LLViewerObject::sendMaterialUpdate() const +{ + LLViewerRegion* regionp = getRegion(); + if(!regionp) return; + gMessageSystem->newMessageFast(_PREHASH_ObjectMaterial); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); + gMessageSystem->addU8Fast(_PREHASH_Material, getMaterial() ); + gMessageSystem->sendReliable( regionp->getHost() ); + +} + +// formerly send_object_rotation +void LLViewerObject::sendRotationUpdate() const +{ + LLViewerRegion* regionp = getRegion(); + if(!regionp) return; + gMessageSystem->newMessageFast(_PREHASH_ObjectRotation); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID); + gMessageSystem->addQuatFast(_PREHASH_Rotation, getRotationEdit()); + //llinfos << "Sent rotation " << getRotationEdit() << llendl; + gMessageSystem->sendReliable( regionp->getHost() ); +} + +/* Obsolete, we use MultipleObjectUpdate instead +//// formerly send_object_position_global +//void LLViewerObject::sendPositionUpdate() const +//{ +// gMessageSystem->newMessageFast(_PREHASH_ObjectPosition); +// gMessageSystem->nextBlockFast(_PREHASH_AgentData); +// gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); +// gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +// gMessageSystem->nextBlockFast(_PREHASH_ObjectData); +// gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); +// gMessageSystem->addVector3Fast(_PREHASH_Position, getPositionRegion()); +// LLViewerRegion* regionp = getRegion(); +// gMessageSystem->sendReliable(regionp->getHost()); +//} +*/ + +//formerly send_object_shape(LLViewerObject *object) +void LLViewerObject::sendShapeUpdate() +{ + gMessageSystem->newMessageFast(_PREHASH_ObjectShape); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); + + LLVolumeMessage::packVolumeParams(&getVolume()->getParams(), gMessageSystem); + + LLViewerRegion *regionp = getRegion(); + gMessageSystem->sendReliable( regionp->getHost() ); +} + + +void LLViewerObject::sendTEUpdate() const +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ObjectImage); + + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); + if (mMedia) + { + msg->addString("MediaURL", mMedia->mMediaURL); + } + else + { + msg->addString("MediaURL", NULL); + } + + // TODO send media type + + packTEMessage(msg); + + LLViewerRegion *regionp = getRegion(); + msg->sendReliable( regionp->getHost() ); +} + +void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry) +{ + LLPrimitive::setTE(te, texture_entry); +// This doesn't work, don't get any textures. +// if (mDrawable.notNull() && mDrawable->isVisible()) +// { + const LLUUID& image_id = getTE(te)->getID(); + mTEImages[te] = LLViewerTextureManager::getFetchedTexture(image_id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); +// } +} + +void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep) +{ + if (mTEImages[te] != imagep) + { + mTEImages[te] = imagep; + LLPrimitive::setTETexture(te, imagep->getID()); + setChanged(TEXTURE); + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + } + } +} + + +S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host) +{ + S32 retval = 0; + if (uuid != getTE(te)->getID() || + uuid == LLUUID::null) + { + retval = LLPrimitive::setTETexture(te, uuid); + mTEImages[te] = LLViewerTextureManager::getFetchedTexture(uuid, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); + setChanged(TEXTURE); + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + } + } + return retval; +} + + +void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) +{ + if(index < 0 || index >= getNumTEs()) + { + return ; + } + mTEImages[index] = new_image ; +} + +S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) +{ + // Invalid host == get from the agent's sim + return setTETextureCore(te, uuid, LLHost::invalid); +} + + +S32 LLViewerObject::setTEColor(const U8 te, const LLColor3& color) +{ + return setTEColor(te, LLColor4(color)); +} + +S32 LLViewerObject::setTEColor(const U8 te, const LLColor4& color) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (color != tep->getColor()) + { + retval = LLPrimitive::setTEColor(te, color); + if (mDrawable.notNull() && retval) + { + // These should only happen on updates which are not the initial update. + dirtyMesh(); + } + } + return retval; +} + +S32 LLViewerObject::setTEBumpmap(const U8 te, const U8 bump) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (bump != tep->getBumpmap()) + { + retval = LLPrimitive::setTEBumpmap(te, bump); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markTextured(mDrawable); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); + } + } + return retval; +} + +S32 LLViewerObject::setTETexGen(const U8 te, const U8 texgen) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (texgen != tep->getTexGen()) + { + retval = LLPrimitive::setTETexGen(te, texgen); + setChanged(TEXTURE); + } + return retval; +} + +S32 LLViewerObject::setTEMediaTexGen(const U8 te, const U8 media) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (media != tep->getMediaTexGen()) + { + retval = LLPrimitive::setTEMediaTexGen(te, media); + setChanged(TEXTURE); + } + return retval; +} + +S32 LLViewerObject::setTEShiny(const U8 te, const U8 shiny) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (shiny != tep->getShiny()) + { + retval = LLPrimitive::setTEShiny(te, shiny); + setChanged(TEXTURE); + } + return retval; +} + +S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (fullbright != tep->getFullbright()) + { + retval = LLPrimitive::setTEFullbright(te, fullbright); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markTextured(mDrawable); + } + } + return retval; +} + + +S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags) +{ + // this might need work for media type + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (media_flags != tep->getMediaFlags()) + { + retval = LLPrimitive::setTEMediaFlags(te, media_flags); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, TRUE); + gPipeline.markTextured(mDrawable); + // JC - probably only need this if changes texture coords + //gPipeline.markRebuild(mDrawable); + } + } + return retval; +} + +S32 LLViewerObject::setTEGlow(const U8 te, const F32 glow) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + } + else if (glow != tep->getGlow()) + { + retval = LLPrimitive::setTEGlow(te, glow); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markTextured(mDrawable); + } + } + return retval; +} + + +S32 LLViewerObject::setTEScale(const U8 te, const F32 s, const F32 t) +{ + S32 retval = 0; + retval = LLPrimitive::setTEScale(te, s, t); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + return retval; +} + +S32 LLViewerObject::setTEScaleS(const U8 te, const F32 s) +{ + S32 retval = LLPrimitive::setTEScaleS(te, s); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + + return retval; +} + +S32 LLViewerObject::setTEScaleT(const U8 te, const F32 t) +{ + S32 retval = LLPrimitive::setTEScaleT(te, t); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + + return retval; +} + +S32 LLViewerObject::setTEOffset(const U8 te, const F32 s, const F32 t) +{ + S32 retval = LLPrimitive::setTEOffset(te, s, t); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + return retval; +} + +S32 LLViewerObject::setTEOffsetS(const U8 te, const F32 s) +{ + S32 retval = LLPrimitive::setTEOffsetS(te, s); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + + return retval; +} + +S32 LLViewerObject::setTEOffsetT(const U8 te, const F32 t) +{ + S32 retval = LLPrimitive::setTEOffsetT(te, t); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + + return retval; +} + +S32 LLViewerObject::setTERotation(const U8 te, const F32 r) +{ + S32 retval = LLPrimitive::setTERotation(te, r); + if (mDrawable.notNull() && retval) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD); + } + return retval; +} + + +LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const +{ +// llassert(mTEImages); + + if (face < getNumTEs()) + { + LLViewerTexture* image = mTEImages[face]; + if (image) + { + return image; + } + else + { + return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); + } + } + + llerrs << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << llendl; + + return NULL; +} + + +void LLViewerObject::fitFaceTexture(const U8 face) +{ + llinfos << "fitFaceTexture not implemented" << llendl; +} + + +LLBBox LLViewerObject::getBoundingBoxAgent() const +{ + LLVector3 position_agent; + LLQuaternion rot; + LLViewerObject* avatar_parent = NULL; + LLViewerObject* root_edit = (LLViewerObject*)getRootEdit(); + if (root_edit) + { + avatar_parent = (LLViewerObject*)root_edit->getParent(); + } + + if (avatar_parent && avatar_parent->isAvatar() && + root_edit && root_edit->mDrawable.notNull() && root_edit->mDrawable->getXform()->getParent()) + { + LLXform* parent_xform = root_edit->mDrawable->getXform()->getParent(); + position_agent = (getPositionEdit() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); + rot = getRotationEdit() * parent_xform->getWorldRotation(); + } + else + { + position_agent = getPositionAgent(); + rot = getRotationRegion(); + } + + return LLBBox( position_agent, rot, getScale() * -0.5f, getScale() * 0.5f ); +} + +U32 LLViewerObject::getNumVertices() const +{ + U32 num_vertices = 0; + if (mDrawable.notNull()) + { + S32 i, num_faces; + num_faces = mDrawable->getNumFaces(); + for (i = 0; i < num_faces; i++) + { + num_vertices += mDrawable->getFace(i)->getGeomCount(); + } + } + return num_vertices; +} + +U32 LLViewerObject::getNumIndices() const +{ + U32 num_indices = 0; + if (mDrawable.notNull()) + { + S32 i, num_faces; + num_faces = mDrawable->getNumFaces(); + for (i = 0; i < num_faces; i++) + { + num_indices += mDrawable->getFace(i)->getIndicesCount(); + } + } + return num_indices; +} + +// Find the number of instances of this object's inventory that are of the given type +S32 LLViewerObject::countInventoryContents(LLAssetType::EType type) +{ + S32 count = 0; + if( mInventory ) + { + LLInventoryObject::object_list_t::const_iterator it = mInventory->begin(); + LLInventoryObject::object_list_t::const_iterator end = mInventory->end(); + for( ; it != end ; ++it ) + { + if( (*it)->getType() == type ) + { + ++count; + } + } + } + return count; +} + + +void LLViewerObject::setCanSelect(BOOL canSelect) +{ + mbCanSelect = canSelect; + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->mbCanSelect = canSelect; + } +} + +void LLViewerObject::setDebugText(const std::string &utf8text) +{ + if (utf8text.empty() && !mText) + { + return; + } + + if (!mText) + { + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); + } + mText->setColor(LLColor4::white); + mText->setString(utf8text); + mText->setZCompare(FALSE); + mText->setDoFade(FALSE); + updateText(); +} + +void LLViewerObject::setIcon(LLViewerTexture* icon_image) +{ + if (!mIcon) + { + mIcon = (LLHUDIcon *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_ICON); + mIcon->setSourceObject(this); + mIcon->setImage(icon_image); + // *TODO: make this user configurable + mIcon->setScale(0.03f); + } + else + { + mIcon->restartLifeTimer(); + } +} + +void LLViewerObject::clearIcon() +{ + if (mIcon) + { + mIcon = NULL; + } +} + +LLViewerObject* LLViewerObject::getSubParent() +{ + if (isJointChild()) + { + return this; + } + return (LLViewerObject*) getParent(); +} + +const LLViewerObject* LLViewerObject::getSubParent() const +{ + if (isJointChild()) + { + return this; + } + return (const LLViewerObject*) getParent(); +} + +BOOL LLViewerObject::isOnMap() +{ + return mOnMap; +} + + +void LLViewerObject::updateText() +{ + if (!isDead()) + { + if (mText.notNull()) + { + LLVector3 up_offset(0,0,0); + up_offset.mV[2] = getScale().mV[VZ]*0.6f; + + if (mDrawable.notNull()) + { + mText->setPositionAgent(getRenderPosition() + up_offset); + } + else + { + mText->setPositionAgent(getPositionAgent() + up_offset); + } + } + } +} + +LLVOAvatar* LLViewerObject::asAvatar() +{ + return NULL; +} + +BOOL LLViewerObject::isParticleSource() const +{ + return !mPartSourcep.isNull() && !mPartSourcep->isDead(); +} + +void LLViewerObject::setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id) +{ + if (mPartSourcep) + { + deleteParticleSource(); + } + + LLPointer<LLViewerPartSourceScript> pss = LLViewerPartSourceScript::createPSS(this, particle_parameters); + mPartSourcep = pss; + + if (mPartSourcep) + { + mPartSourcep->setOwnerUUID(owner_id); + + if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) + { + LLViewerTexture* image; + if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) + { + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.tga"); + } + else + { + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); + } + mPartSourcep->setImage(image); + } + } + LLViewerPartSim::getInstance()->addPartSource(pss); +} + +void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& owner_id) +{ + if (!mPartSourcep.isNull() && mPartSourcep->isDead()) + { + mPartSourcep = NULL; + } + if (mPartSourcep) + { + // If we've got one already, just update the existing source (or remove it) + if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, block_num)) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } + } + else + { + LLPointer<LLViewerPartSourceScript> pss = LLViewerPartSourceScript::unpackPSS(this, NULL, block_num); + //If the owner is muted, don't create the system + if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return; + + // We need to be able to deal with a particle source that hasn't changed, but still got an update! + if (pss) + { +// llinfos << "Making particle system with owner " << owner_id << llendl; + pss->setOwnerUUID(owner_id); + mPartSourcep = pss; + LLViewerPartSim::getInstance()->addPartSource(pss); + } + } + if (mPartSourcep) + { + if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) + { + LLViewerTexture* image; + if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) + { + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); + } + else + { + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); + } + mPartSourcep->setImage(image); + } + } +} + +void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id) +{ + if (!mPartSourcep.isNull() && mPartSourcep->isDead()) + { + mPartSourcep = NULL; + } + if (mPartSourcep) + { + // If we've got one already, just update the existing source (or remove it) + if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, dp)) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } + } + else + { + LLPointer<LLViewerPartSourceScript> pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp); + //If the owner is muted, don't create the system + if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return; + // We need to be able to deal with a particle source that hasn't changed, but still got an update! + if (pss) + { +// llinfos << "Making particle system with owner " << owner_id << llendl; + pss->setOwnerUUID(owner_id); + mPartSourcep = pss; + LLViewerPartSim::getInstance()->addPartSource(pss); + } + } + if (mPartSourcep) + { + if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) + { + LLViewerTexture* image; + if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) + { + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); + } + else + { + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); + } + mPartSourcep->setImage(image); + } + } +} + +void LLViewerObject::deleteParticleSource() +{ + if (mPartSourcep.notNull()) + { + mPartSourcep->setDead(); + mPartSourcep = NULL; + } +} + +// virtual +void LLViewerObject::updateDrawable(BOOL force_damped) +{ + if (mDrawable.notNull() && + !mDrawable->isState(LLDrawable::ON_MOVE_LIST) && + isChanged(MOVED)) + { + BOOL damped_motion = + !isChanged(SHIFTED) && // not shifted between regions this frame and... + ( force_damped || // ...forced into damped motion by application logic or... + ( !isSelected() && // ...not selected and... + ( mDrawable->isRoot() || // ... is root or ... + (getParent() && !((LLViewerObject*)getParent())->isSelected())// ... parent is not selected and ... + ) && + getPCode() == LL_PCODE_VOLUME && // ...is a volume object and... + getVelocity().isExactlyZero() && // ...is not moving physically and... + mDrawable->getGeneration() != -1 // ...was not created this frame. + ) + ); + gPipeline.markMoved(mDrawable, damped_motion); + } + clearChanged(SHIFTED); +} + +// virtual, overridden by LLVOVolume +F32 LLViewerObject::getVObjRadius() const +{ + return mDrawable.notNull() ? mDrawable->getRadius() : 0.f; +} + +void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags) +{ + if (!gAudiop) + { + return; + } + + if (audio_uuid.isNull()) + { + if (!mAudioSourcep) + { + return; + } + if (mAudioSourcep->isLoop() && !mAudioSourcep->hasPendingPreloads()) + { + // We don't clear the sound if it's a loop, it'll go away on its own. + // At least, this appears to be how the scripts work. + // The attached sound ID is set to NULL to avoid it playing back when the + // object rezzes in on non-looping sounds. + //llinfos << "Clearing attached sound " << mAudioSourcep->getCurrentData()->getID() << llendl; + gAudiop->cleanupAudioSource(mAudioSourcep); + mAudioSourcep = NULL; + } + else if (flags & LL_SOUND_FLAG_STOP) + { + // Just shut off the sound + mAudioSourcep->play(LLUUID::null); + } + return; + } + if (flags & LL_SOUND_FLAG_LOOP + && mAudioSourcep && mAudioSourcep->isLoop() && mAudioSourcep->getCurrentData() + && mAudioSourcep->getCurrentData()->getID() == audio_uuid) + { + //llinfos << "Already playing this sound on a loop, ignoring" << llendl; + return; + } + + // don't clean up before previous sound is done. Solves: SL-33486 + if ( mAudioSourcep && mAudioSourcep->isDone() ) + { + gAudiop->cleanupAudioSource(mAudioSourcep); + mAudioSourcep = NULL; + } + + if (mAudioSourcep && mAudioSourcep->isMuted() && + mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) + { + //llinfos << "Already having this sound as muted sound, ignoring" << llendl; + return; + } + + getAudioSource(owner_id); + + if (mAudioSourcep) + { + BOOL queue = flags & LL_SOUND_FLAG_QUEUE; + mAudioGain = gain; + mAudioSourcep->setGain(gain); + mAudioSourcep->setLoop(flags & LL_SOUND_FLAG_LOOP); + mAudioSourcep->setSyncMaster(flags & LL_SOUND_FLAG_SYNC_MASTER); + mAudioSourcep->setSyncSlave(flags & LL_SOUND_FLAG_SYNC_SLAVE); + mAudioSourcep->setQueueSounds(queue); + if(!queue) // stop any current sound first to avoid "farts of doom" (SL-1541) -MG + { + mAudioSourcep->play(LLUUID::null); + } + + // Play this sound if region maturity permits + if( gAgent.canAccessMaturityAtGlobal(this->getPositionGlobal()) ) + { + //llinfos << "Playing attached sound " << audio_uuid << llendl; + mAudioSourcep->play(audio_uuid); + } + } +} + +LLAudioSource *LLViewerObject::getAudioSource(const LLUUID& owner_id) +{ + if (!mAudioSourcep) + { + // Arbitrary low gain for a sound that's not playing. + // This is used for sound preloads, for example. + LLAudioSourceVO *asvop = new LLAudioSourceVO(mID, owner_id, 0.01f, this); + + mAudioSourcep = asvop; + if(gAudiop) gAudiop->addAudioSource(asvop); + } + + return mAudioSourcep; +} + +void LLViewerObject::adjustAudioGain(const F32 gain) +{ + if (!gAudiop) + { + return; + } + if (mAudioSourcep) + { + mAudioGain = gain; + mAudioSourcep->setGain(mAudioGain); + } +} + +//---------------------------------------------------------------------------- + +bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp) +{ + ExtraParameter* param = getExtraParameterEntryCreate(param_type); + if (param) + { + param->data->unpack(*dp); + param->in_use = TRUE; + parameterChanged(param_type, param->data, TRUE, false); + return true; + } + else + { + return false; + } +} + +LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 param_type) +{ + LLNetworkData* new_block = NULL; + switch (param_type) + { + case LLNetworkData::PARAMS_FLEXIBLE: + { + new_block = new LLFlexibleObjectData(); + break; + } + case LLNetworkData::PARAMS_LIGHT: + { + new_block = new LLLightParams(); + break; + } + case LLNetworkData::PARAMS_SCULPT: + { + new_block = new LLSculptParams(); + break; + } + case LLNetworkData::PARAMS_LIGHT_IMAGE: + { + new_block = new LLLightImageParams(); + break; + } + default: + { + llinfos << "Unknown param type." << llendl; + break; + } + }; + + if (new_block) + { + ExtraParameter* new_entry = new ExtraParameter; + new_entry->data = new_block; + new_entry->in_use = false; // not in use yet + mExtraParameterList[param_type] = new_entry; + return new_entry; + } + return NULL; +} + +LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntry(U16 param_type) const +{ + std::map<U16, ExtraParameter*>::const_iterator itor = mExtraParameterList.find(param_type); + if (itor != mExtraParameterList.end()) + { + return itor->second; + } + return NULL; +} + +LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntryCreate(U16 param_type) +{ + ExtraParameter* param = getExtraParameterEntry(param_type); + if (!param) + { + param = createNewParameterEntry(param_type); + } + return param; +} + +LLNetworkData* LLViewerObject::getParameterEntry(U16 param_type) const +{ + ExtraParameter* param = getExtraParameterEntry(param_type); + if (param) + { + return param->data; + } + else + { + return NULL; + } +} + +BOOL LLViewerObject::getParameterEntryInUse(U16 param_type) const +{ + ExtraParameter* param = getExtraParameterEntry(param_type); + if (param) + { + return param->in_use; + } + else + { + return FALSE; + } +} + +bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin) +{ + ExtraParameter* param = getExtraParameterEntryCreate(param_type); + if (param) + { + if (param->in_use && new_value == *(param->data)) + { + return false; + } + param->in_use = true; + param->data->copy(new_value); + parameterChanged(param_type, param->data, TRUE, local_origin); + return true; + } + else + { + return false; + } +} + +// Assumed to be called locally +// If in_use is TRUE, will crate a new extra parameter if none exists. +// Should always return true. +bool LLViewerObject::setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin) +{ + ExtraParameter* param = getExtraParameterEntryCreate(param_type); + if (param && param->in_use != in_use) + { + param->in_use = in_use; + parameterChanged(param_type, param->data, in_use, local_origin); + return true; + } + return false; +} + +void LLViewerObject::parameterChanged(U16 param_type, bool local_origin) +{ + ExtraParameter* param = getExtraParameterEntry(param_type); + if (param) + { + parameterChanged(param_type, param->data, param->in_use, local_origin); + } +} + +void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin) +{ + if (local_origin) + { + LLViewerRegion* regionp = getRegion(); + if(!regionp) return; + + // Change happened on the viewer. Send the change up + U8 tmp[MAX_OBJECT_PARAMS_SIZE]; + LLDataPackerBinaryBuffer dpb(tmp, MAX_OBJECT_PARAMS_SIZE); + if (data->pack(dpb)) + { + U32 datasize = (U32)dpb.getCurrentSize(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ObjectExtraParams); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID ); + + msg->addU16Fast(_PREHASH_ParamType, param_type); + msg->addBOOLFast(_PREHASH_ParamInUse, in_use); + + msg->addU32Fast(_PREHASH_ParamSize, datasize); + msg->addBinaryDataFast(_PREHASH_ParamData, tmp, datasize); + + msg->sendReliable( regionp->getHost() ); + } + else + { + llwarns << "Failed to send object extra parameters: " << param_type << llendl; + } + } +} + +void LLViewerObject::setDrawableState(U32 state, BOOL recursive) +{ + if (mDrawable) + { + mDrawable->setState(state); + } + if (recursive) + { + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->setDrawableState(state, recursive); + } + } +} + +void LLViewerObject::clearDrawableState(U32 state, BOOL recursive) +{ + if (mDrawable) + { + mDrawable->clearState(state); + } + if (recursive) + { + for (child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->clearDrawableState(state, recursive); + } + } +} + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// RN: these functions assume a 2-level hierarchy +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// Owned by anyone? +BOOL LLViewerObject::permAnyOwner() const +{ + if (isRootEdit()) + { + return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0); + } + else + { + return ((LLViewerObject*)getParent())->permAnyOwner(); + } +} +// Owned by this viewer? +BOOL LLViewerObject::permYouOwner() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permYouOwner(); + } +} + +// Owned by a group? +BOOL LLViewerObject::permGroupOwner() const +{ + if (isRootEdit()) + { + return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0); + } + else + { + return ((LLViewerObject*)getParent())->permGroupOwner(); + } +} + +// Can the owner edit +BOOL LLViewerObject::permOwnerModify() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permOwnerModify(); + } +} + +// Can edit +BOOL LLViewerObject::permModify() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_MODIFY) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permModify(); + } +} + +// Can copy +BOOL LLViewerObject::permCopy() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_COPY) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permCopy(); + } +} + +// Can move +BOOL LLViewerObject::permMove() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_MOVE) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permMove(); + } +} + +// Can be transferred +BOOL LLViewerObject::permTransfer() const +{ + if (isRootEdit()) + { +#ifdef HACKED_GODLIKE_VIEWER + return TRUE; +#else +# ifdef TOGGLE_HACKED_GODLIKE_VIEWER + if (!LLGridManager::getInstance()->isInProductionGrid() + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + { + return TRUE; + } +# endif + return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0); +#endif + } + else + { + return ((LLViewerObject*)getParent())->permTransfer(); + } +} + +// Can only open objects that you own, or that someone has +// given you modify rights to. JC +BOOL LLViewerObject::allowOpen() const +{ + return !flagInventoryEmpty() && (permYouOwner() || permModify()); +} + +LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo() +{ + if (mListener) + { + mListener->clearVOInventoryListener(); + } +} + +void LLViewerObject::updateVolume(const LLVolumeParams& volume_params) +{ + if (setVolume(volume_params, 1)) // *FIX: magic number, ack! + { + // Transmit the update to the simulator + sendShapeUpdate(); + markForUpdate(TRUE); + } +} + +void LLViewerObject::markForUpdate(BOOL priority) +{ + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, priority); + } +} + +bool LLViewerObject::getIncludeInSearch() const +{ + return ((mFlags & FLAGS_INCLUDE_IN_SEARCH) != 0); +} + +void LLViewerObject::setIncludeInSearch(bool include_in_search) +{ + if (include_in_search) + { + mFlags |= FLAGS_INCLUDE_IN_SEARCH; + } + else + { + mFlags &= ~FLAGS_INCLUDE_IN_SEARCH; + } +} + +void LLViewerObject::setRegion(LLViewerRegion *regionp) +{ + if (!regionp) + { + llwarns << "viewer object set region to NULL" << llendl; + } + + mLatestRecvPacketID = 0; + mRegionp = regionp; + + for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) + { + LLViewerObject* child = *i; + child->setRegion(regionp); + } + + setChanged(MOVED | SILHOUETTE); + updateDrawable(FALSE); +} + +// virtual +void LLViewerObject::updateRegion(LLViewerRegion *regionp) +{ +// if (regionp) +// { +// F64 now = LLFrameTimer::getElapsedSeconds(); +// llinfos << "Updating to region " << regionp->getName() +// << ", ms since last update message: " << (F32)((now - mLastMessageUpdateSecs) * 1000.0) +// << ", ms since last interpolation: " << (F32)((now - mLastInterpUpdateSecs) * 1000.0) +// << llendl; +// } +} + + +bool LLViewerObject::specialHoverCursor() const +{ + return (mFlags & FLAGS_USE_PHYSICS) + || (mFlags & FLAGS_HANDLE_TOUCH) + || (mClickAction != 0); +} + +void LLViewerObject::updateFlags(BOOL physics_changed) +{ + LLViewerRegion* regionp = getRegion(); + if(!regionp) return; + gMessageSystem->newMessage("ObjectFlagUpdate"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, getLocalID() ); + gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, usePhysics() ); + gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); + gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); + gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); + if (physics_changed) + { + gMessageSystem->nextBlock("ExtraPhysics"); + gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() ); + gMessageSystem->addF32("Density", getPhysicsDensity() ); + gMessageSystem->addF32("Friction", getPhysicsFriction() ); + gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); + gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); + } + gMessageSystem->sendReliable( regionp->getHost() ); +} + +BOOL LLViewerObject::setFlags(U32 flags, BOOL state) +{ + BOOL setit = FALSE; + if (state) + { + if ((mFlags & flags) != flags) + { + mFlags |= flags; + setit = TRUE; + } + } + else + { + if ((mFlags & flags) != 0) + { + mFlags &= ~flags; + setit = TRUE; + } + } + + // BUG: Sometimes viewer physics and simulator physics get + // out of sync. To fix this, always send update to simulator. +// if (setit) + { + updateFlags(); + } + return setit; +} + +void LLViewerObject::setPhysicsShapeType(U8 type) +{ + mPhysicsShapeUnknown = false; + mPhysicsShapeType = type; + mCostStale = true; +} + +void LLViewerObject::setPhysicsGravity(F32 gravity) +{ + mPhysicsGravity = gravity; +} + +void LLViewerObject::setPhysicsFriction(F32 friction) +{ + mPhysicsFriction = friction; +} + +void LLViewerObject::setPhysicsDensity(F32 density) +{ + mPhysicsDensity = density; +} + +void LLViewerObject::setPhysicsRestitution(F32 restitution) +{ + mPhysicsRestitution = restitution; +} + +U8 LLViewerObject::getPhysicsShapeType() const +{ + if (mPhysicsShapeUnknown) + { + mPhysicsShapeUnknown = false; + gObjectList.updatePhysicsFlags(this); + } + + return mPhysicsShapeType; +} + +void LLViewerObject::applyAngularVelocity(F32 dt) +{ + //do target omega here + mRotTime += dt; + LLVector3 ang_vel = getAngularVelocity(); + F32 omega = ang_vel.magVecSquared(); + F32 angle = 0.0f; + LLQuaternion dQ; + if (omega > 0.00001f) + { + omega = sqrt(omega); + angle = omega * dt; + + ang_vel *= 1.f/omega; + + dQ.setQuat(angle, ang_vel); + + setRotation(getRotation()*dQ); + setChanged(MOVED | SILHOUETTE); + } +} + +void LLViewerObject::resetRot() +{ + mRotTime = 0.0f; +} + +U32 LLViewerObject::getPartitionType() const +{ + return LLViewerRegion::PARTITION_NONE; +} + +void LLViewerObject::dirtySpatialGroup(BOOL priority) const +{ + if (mDrawable) + { + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->dirtyGeom(); + gPipeline.markRebuild(group, priority); + } + } +} + +void LLViewerObject::dirtyMesh() +{ + if (mDrawable) + { + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->dirtyMesh(); + } + } +} + +F32 LLAlphaObject::getPartSize(S32 idx) +{ + return 0.f; +} + +// virtual +void LLStaticViewerObject::updateDrawable(BOOL force_damped) +{ + // Force an immediate rebuild on any update + if (mDrawable.notNull()) + { + mDrawable->updateXform(TRUE); + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); + } + clearChanged(SHIFTED); +} + +void LLViewerObject::saveUnselectedChildrenPosition(std::vector<LLVector3>& positions) +{ + if(mChildList.empty() || !positions.empty()) + { + return ; + } + + for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* childp = *iter; + if (!childp->isSelected() && childp->mDrawable.notNull()) + { + positions.push_back(childp->getPositionEdit()); + } + } + + return ; +} + +void LLViewerObject::saveUnselectedChildrenRotation(std::vector<LLQuaternion>& rotations) +{ + if(mChildList.empty()) + { + return ; + } + + for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* childp = *iter; + if (!childp->isSelected() && childp->mDrawable.notNull()) + { + rotations.push_back(childp->getRotationEdit()); + } + } + + return ; +} + +//counter-rotation +void LLViewerObject::resetChildrenRotationAndPosition(const std::vector<LLQuaternion>& rotations, + const std::vector<LLVector3>& positions) +{ + if(mChildList.empty()) + { + return ; + } + + S32 index = 0 ; + LLQuaternion inv_rotation = ~getRotationEdit() ; + LLVector3 offset = getPositionEdit() ; + for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* childp = *iter; + if (!childp->isSelected() && childp->mDrawable.notNull()) + { + if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) + { + childp->setRotation(rotations[index] * inv_rotation); + childp->setPosition((positions[index] - offset) * inv_rotation); + LLManip::rebuild(childp); + } + else //avatar + { + LLVector3 reset_pos = (positions[index] - offset) * inv_rotation ; + LLQuaternion reset_rot = rotations[index] * inv_rotation ; + + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->mXform.setRotation(reset_rot) ; + + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setRotation(reset_rot, TRUE) ; + + LLManip::rebuild(childp); + } + index++; + } + } + + return ; +} + +//counter-translation +void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified) +{ + if(mChildList.empty()) + { + return ; + } + + LLVector3 child_offset; + if(simplified) //translation only, rotation matrix does not change + { + child_offset = offset * ~getRotation(); + } + else //rotation matrix might change too. + { + if (isAttachment() && mDrawable.notNull()) + { + LLXform* attachment_point_xform = mDrawable->getXform()->getParent(); + LLQuaternion parent_rotation = getRotation() * attachment_point_xform->getWorldRotation(); + child_offset = offset * ~parent_rotation; + } + else + { + child_offset = offset * ~getRenderRotation(); + } + } + + for (LLViewerObject::child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* childp = *iter; + if (!childp->isSelected() && childp->mDrawable.notNull()) + { + if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) + { + childp->setPosition(childp->getPosition() + child_offset); + LLManip::rebuild(childp); + } + else //avatar + { + LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; + + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); + + LLManip::rebuild(childp); + } + } + } + + return ; +} + +const LLUUID &LLViewerObject::getAttachmentItemID() const +{ + return mAttachmentItemID; +} + +void LLViewerObject::setAttachmentItemID(const LLUUID &id) +{ + mAttachmentItemID = id; +} + +EObjectUpdateType LLViewerObject::getLastUpdateType() const +{ + return mLastUpdateType; +} + +void LLViewerObject::setLastUpdateType(EObjectUpdateType last_update_type) +{ + mLastUpdateType = last_update_type; +} + +BOOL LLViewerObject::getLastUpdateCached() const +{ + return mLastUpdateCached; +} + +void LLViewerObject::setLastUpdateCached(BOOL last_update_cached) +{ + mLastUpdateCached = last_update_cached; +} + +const LLUUID &LLViewerObject::extractAttachmentItemID() +{ + LLUUID item_id = LLUUID::null; + LLNameValue* item_id_nv = getNVPair("AttachItemID"); + if( item_id_nv ) + { + const char* s = item_id_nv->getString(); + if( s ) + { + item_id.set(s); + } + } + setAttachmentItemID(item_id); + return getAttachmentItemID(); +} + +//virtual +LLVOAvatar* LLViewerObject::getAvatar() const +{ + if (isAttachment()) + { + LLViewerObject* vobj = (LLViewerObject*) getParent(); + + while (vobj && !vobj->asAvatar()) + { + vobj = (LLViewerObject*) vobj->getParent(); + } + + return (LLVOAvatar*) vobj; + } + + return NULL; +} + + +class ObjectPhysicsProperties : public LLHTTPNode +{ +public: + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + LLSD object_data = input["body"]["ObjectData"]; + S32 num_entries = object_data.size(); + + for ( S32 i = 0; i < num_entries; i++ ) + { + LLSD& curr_object_data = object_data[i]; + U32 local_id = curr_object_data["LocalID"].asInteger(); + + // Iterate through nodes at end, since it can be on both the regular AND hover list + struct f : public LLSelectedNodeFunctor + { + U32 mID; + f(const U32& id) : mID(id) {} + virtual bool apply(LLSelectNode* node) + { + return (node->getObject() && node->getObject()->mLocalID == mID ); + } + } func(local_id); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func); + + if (node) + { + // The LLSD message builder doesn't know how to handle U8, so we need to send as S8 and cast + U8 type = (U8)curr_object_data["PhysicsShapeType"].asInteger(); + F32 density = (F32)curr_object_data["Density"].asReal(); + F32 friction = (F32)curr_object_data["Friction"].asReal(); + F32 restitution = (F32)curr_object_data["Restitution"].asReal(); + F32 gravity = (F32)curr_object_data["GravityMultiplier"].asReal(); + + node->getObject()->setPhysicsShapeType(type); + node->getObject()->setPhysicsGravity(gravity); + node->getObject()->setPhysicsFriction(friction); + node->getObject()->setPhysicsDensity(density); + node->getObject()->setPhysicsRestitution(restitution); + } + } + + dialog_refresh_all(); + }; +}; + +LLHTTPRegistration<ObjectPhysicsProperties> + gHTTPRegistrationObjectPhysicsProperties("/message/ObjectPhysicsProperties"); + + +void LLViewerObject::updateQuota( const SelectionQuota& quota ) +{ + //update quotas + mSelectionQuota = quota; +} diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 1335c5c319..a0ad52df6b 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -1,825 +1,825 @@ -/**
- * @file llviewerobject.h
- * @brief Description of LLViewerObject class, which is the base class for most objects in the viewer.
- *
- * $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$
- */
-
-#ifndef LL_LLVIEWEROBJECT_H
-#define LL_LLVIEWEROBJECT_H
-
-#include <map>
-
-#include "llassetstorage.h"
-#include "lldarrayptr.h"
-#include "llhudicon.h"
-#include "llinventory.h"
-#include "llrefcount.h"
-#include "llmemtype.h"
-#include "llprimitive.h"
-#include "lluuid.h"
-#include "llvoinventorylistener.h"
-#include "object_flags.h"
-#include "llquaternion.h"
-#include "v3dmath.h"
-#include "v3math.h"
-#include "llvertexbuffer.h"
-#include "llaccountingquota.h"
-
-class LLAgent; // TODO: Get rid of this.
-class LLAudioSource;
-class LLAudioSourceVO;
-class LLBBox;
-class LLDataPacker;
-class LLColor4;
-class LLFrameTimer;
-class LLDrawable;
-class LLHost;
-class LLHUDText;
-class LLWorld;
-class LLNameValue;
-class LLNetMap;
-class LLMessageSystem;
-class LLPartSysData;
-class LLPrimitive;
-class LLPipeline;
-class LLTextureEntry;
-class LLViewerTexture;
-class LLViewerInventoryItem;
-class LLViewerObject;
-class LLViewerPartSourceScript;
-class LLViewerRegion;
-class LLViewerObjectMedia;
-class LLVOInventoryListener;
-class LLVOAvatar;
-
-typedef enum e_object_update_type
-{
- OUT_FULL,
- OUT_TERSE_IMPROVED,
- OUT_FULL_COMPRESSED,
- OUT_FULL_CACHED,
- OUT_UNKNOWN,
-} EObjectUpdateType;
-
-
-// callback typedef for inventory
-typedef void (*inventory_callback)(LLViewerObject*,
- LLInventoryObject::object_list_t*,
- S32 serial_num,
- void*);
-
-// a small struct for keeping track of joints
-struct LLVOJointInfo
-{
- EHavokJointType mJointType;
- LLVector3 mPivot; // parent-frame
- // whether the below an axis or anchor (and thus its frame)
- // depends on the joint type:
- // HINGE ==> axis=parent-frame
- // P2P ==> anchor=child-frame
- LLVector3 mAxisOrAnchor;
-};
-
-// for exporting textured materials from SL
-struct LLMaterialExportInfo
-{
-public:
- LLMaterialExportInfo(S32 mat_index, S32 texture_index, LLColor4 color) :
- mMaterialIndex(mat_index), mTextureIndex(texture_index), mColor(color) {};
-
- S32 mMaterialIndex;
- S32 mTextureIndex;
- LLColor4 mColor;
-};
-
-//============================================================================
-
-class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
-{
-protected:
- ~LLViewerObject(); // use unref()
-
- // TomY: Provide for a list of extra parameter structures, mapped by structure name
- struct ExtraParameter
- {
- BOOL in_use;
- LLNetworkData *data;
- };
- std::map<U16, ExtraParameter*> mExtraParameterList;
-
-public:
- typedef std::list<LLPointer<LLViewerObject> > child_list_t;
- typedef std::list<LLPointer<LLViewerObject> > vobj_list_t;
-
- typedef const child_list_t const_child_list_t;
-
- LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global = FALSE);
- MEM_TYPE_NEW(LLMemType::MTYPE_OBJECT);
-
- virtual void markDead(); // Mark this object as dead, and clean up its references
- BOOL isDead() const {return mDead;}
- BOOL isOrphaned() const { return mOrphaned; }
- BOOL isParticleSource() const;
-
- virtual LLVOAvatar* asAvatar();
-
- static void initVOClasses();
- static void cleanupVOClasses();
-
- void addNVPair(const std::string& data);
- BOOL removeNVPair(const std::string& name);
- LLNameValue* getNVPair(const std::string& name) const; // null if no name value pair by that name
-
- // Object create and update functions
- virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
-
- // Types of media we can associate
- enum { MEDIA_NONE = 0, MEDIA_SET = 1 };
-
- // Return codes for processUpdateMessage
- enum {
- MEDIA_URL_REMOVED = 0x1,
- MEDIA_URL_ADDED = 0x2,
- MEDIA_URL_UPDATED = 0x4,
- MEDIA_FLAGS_CHANGED = 0x8,
- INVALID_UPDATE = 0x80000000
- };
-
- virtual U32 processUpdateMessage(LLMessageSystem *mesgsys,
- void **user_data,
- U32 block_num,
- const EObjectUpdateType update_type,
- LLDataPacker *dp);
-
-
- virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate.
- BOOL onActiveList() const {return mOnActiveList;}
- void setOnActiveList(BOOL on_active) { mOnActiveList = on_active; }
-
- virtual BOOL isAttachment() const { return FALSE; }
- virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment
- virtual BOOL isHUDAttachment() const { return FALSE; }
- virtual void updateRadius() {};
- virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius()
-
- BOOL isJointChild() const { return mJointInfo ? TRUE : FALSE; }
- EHavokJointType getJointType() const { return mJointInfo ? mJointInfo->mJointType : HJT_INVALID; }
- // for jointed and other parent-relative hacks
- LLViewerObject* getSubParent();
- const LLViewerObject* getSubParent() const;
-
- // Object visiblility and GPW functions
- virtual void setPixelAreaAndAngle(LLAgent &agent); // Override to generate accurate apparent angle and area
-
- virtual U32 getNumVertices() const;
- virtual U32 getNumIndices() const;
- S32 getNumFaces() const { return mNumFaces; }
-
- // Graphical stuff for objects - maybe broken out into render class later?
- virtual void updateTextures();
- virtual void boostTexturePriority(BOOL boost_children = TRUE); // When you just want to boost priority of this object
-
- virtual LLDrawable* createDrawable(LLPipeline *pipeline);
- virtual BOOL updateGeometry(LLDrawable *drawable);
- virtual void updateGL();
- virtual void updateFaceSize(S32 idx);
- virtual BOOL updateLOD();
- virtual BOOL setDrawableParent(LLDrawable* parentp);
- F32 getRotTime() { return mRotTime; }
- void resetRot();
- void applyAngularVelocity(F32 dt);
-
- void setLineWidthForWindowSize(S32 window_width);
-
- static void increaseArrowLength(); // makes axis arrows for selections longer
- static void decreaseArrowLength(); // makes axis arrows for selections shorter
-
- // Accessor functions
- LLViewerRegion* getRegion() const { return mRegionp; }
-
- BOOL isSelected() const { return mUserSelected; }
- virtual void setSelected(BOOL sel) { mUserSelected = sel; mRotTime = 0.f;}
-
- const LLUUID &getID() const { return mID; }
- U32 getLocalID() const { return mLocalID; }
- U32 getCRC() const { return mTotalCRC; }
-
- virtual BOOL isFlexible() const { return FALSE; }
- virtual BOOL isSculpted() const { return FALSE; }
- virtual BOOL isMesh() const { return FALSE; }
- virtual BOOL hasLightTexture() const { return FALSE; }
-
- // This method returns true if the object is over land owned by
- // the agent, one of its groups, or it encroaches and
- // anti-encroachment is enabled
- bool isReturnable();
-
- /*
- // This method will scan through this object, and then query the
- // selection manager to see if the local agent probably has the
- // ability to modify the object. Since this calls into the
- // selection manager, you should avoid calling this method from
- // there.
- BOOL isProbablyModifiable() const;
- */
-
- virtual BOOL setParent(LLViewerObject* parent);
- virtual void addChild(LLViewerObject *childp);
- virtual void removeChild(LLViewerObject *childp);
- const_child_list_t& getChildren() const { return mChildList; }
- S32 numChildren() const { return mChildList.size(); }
- void addThisAndAllChildren(std::vector<LLViewerObject*>& objects);
- void addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects);
- BOOL isChild(LLViewerObject *childp) const;
- BOOL isSeat() const;
-
-
- //detect if given line segment (in agent space) intersects with this viewer object.
- //returns TRUE if intersection detected and returns information about intersection
- virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
- S32 face = -1, // which face to check, -1 = ALL_SIDES
- BOOL pick_transparent = FALSE,
- S32* face_hit = NULL, // which face was hit
- LLVector3* intersection = NULL, // return the intersection point
- LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
- LLVector3* normal = NULL, // return the surface normal at the intersection point
- LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point
- );
-
- virtual BOOL lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end);
-
- virtual const LLVector3d getPositionGlobal() const;
- virtual const LLVector3 &getPositionRegion() const;
- virtual const LLVector3 getPositionEdit() const;
- virtual const LLVector3 &getPositionAgent() const;
- virtual const LLVector3 getRenderPosition() const;
-
- virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not
-
- LLViewerObject* getRootEdit() const;
-
- const LLQuaternion getRotationRegion() const;
- const LLQuaternion getRotationEdit() const;
- const LLQuaternion getRenderRotation() const;
- virtual const LLMatrix4 getRenderMatrix() const;
-
- void setPosition(const LLVector3 &pos, BOOL damped = FALSE);
- void setPositionGlobal(const LLVector3d &position, BOOL damped = FALSE);
- void setPositionRegion(const LLVector3 &position, BOOL damped = FALSE);
- void setPositionEdit(const LLVector3 &position, BOOL damped = FALSE);
- void setPositionAgent(const LLVector3 &pos_agent, BOOL damped = FALSE);
- void setPositionParent(const LLVector3 &pos_parent, BOOL damped = FALSE);
- void setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped = FALSE );
-
- virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const { return xform->getWorldMatrix(); }
-
- inline void setRotation(const F32 x, const F32 y, const F32 z, BOOL damped = FALSE);
- inline void setRotation(const LLQuaternion& quat, BOOL damped = FALSE);
- void sendRotationUpdate() const;
-
- /*virtual*/ void setNumTEs(const U8 num_tes);
- /*virtual*/ void setTE(const U8 te, const LLTextureEntry &texture_entry);
- /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid);
- S32 setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host);
- /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color);
- /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color);
- /*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t);
- /*virtual*/ S32 setTEScaleS(const U8 te, const F32 s);
- /*virtual*/ S32 setTEScaleT(const U8 te, const F32 t);
- /*virtual*/ S32 setTEOffset(const U8 te, const F32 s, const F32 t);
- /*virtual*/ S32 setTEOffsetS(const U8 te, const F32 s);
- /*virtual*/ S32 setTEOffsetT(const U8 te, const F32 t);
- /*virtual*/ S32 setTERotation(const U8 te, const F32 r);
- /*virtual*/ S32 setTEBumpmap(const U8 te, const U8 bump );
- /*virtual*/ S32 setTETexGen(const U8 te, const U8 texgen );
- /*virtual*/ S32 setTEMediaTexGen(const U8 te, const U8 media ); // *FIXME: this confusingly acts upon a superset of setTETexGen's flags without absorbing its semantics
- /*virtual*/ S32 setTEShiny(const U8 te, const U8 shiny );
- /*virtual*/ S32 setTEFullbright(const U8 te, const U8 fullbright );
- /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags );
- /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow);
- /*virtual*/ BOOL setMaterial(const U8 material);
- virtual void setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive
- void changeTEImage(S32 index, LLViewerTexture* new_image) ;
- LLViewerTexture *getTEImage(const U8 te) const;
-
- void fitFaceTexture(const U8 face);
- void sendTEUpdate() const; // Sends packed representation of all texture entry information
-
- virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE);
-
- virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL);
- virtual U32 getTriangleCount();
- virtual U32 getHighLODTriangleCount();
-
- void setObjectCost(F32 cost);
- F32 getObjectCost();
-
- void setLinksetCost(F32 cost);
- F32 getLinksetCost();
-
- void setPhysicsCost(F32 cost);
- F32 getPhysicsCost();
-
- void setLinksetPhysicsCost(F32 cost);
- F32 getLinksetPhysicsCost();
-
- void sendShapeUpdate();
-
- U8 getState() { return mState; }
-
- F32 getAppAngle() const { return mAppAngle; }
- F32 getPixelArea() const { return mPixelArea; }
- void setPixelArea(F32 area) { mPixelArea = area; }
- F32 getMaxScale() const;
- F32 getMidScale() const;
- F32 getMinScale() const;
-
- // Owner id is this object's owner
- void setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags);
- void adjustAudioGain(const F32 gain);
- void clearAttachedSound() { mAudioSourcep = NULL; }
-
- // Create if necessary
- LLAudioSource *getAudioSource(const LLUUID& owner_id);
- bool isAudioSource() {return mAudioSourcep != NULL;}
-
- U8 getMediaType() const;
- void setMediaType(U8 media_type);
-
- std::string getMediaURL() const;
- void setMediaURL(const std::string& media_url);
-
- BOOL getMediaPassedWhitelist() const;
- void setMediaPassedWhitelist(BOOL passed);
-
- void sendMaterialUpdate() const;
-
- void setCanSelect(BOOL canSelect);
-
- void setDebugText(const std::string &utf8text);
- void setIcon(LLViewerTexture* icon_image);
- void clearIcon();
-
- void markForUpdate(BOOL priority);
- void updateVolume(const LLVolumeParams& volume_params);
- virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max);
- virtual F32 getBinRadius();
-
- LLBBox getBoundingBoxAgent() const;
-
- void updatePositionCaches() const; // Update the global and region position caches from the object (and parent's) xform.
- void updateText(); // update text label position
- virtual void updateDrawable(BOOL force_damped); // force updates on static objects
-
- void setDrawableState(U32 state, BOOL recursive = TRUE);
- void clearDrawableState(U32 state, BOOL recursive = TRUE);
-
- // Called when the drawable shifts
- virtual void onShift(const LLVector4a &shift_vector) { }
-
- //////////////////////////////////////
- //
- // Inventory methods
- //
-
- // This function is called when someone is interested in a viewer
- // object's inventory. The callback is called as soon as the
- // viewer object has the inventory stored locally.
- void registerInventoryListener(LLVOInventoryListener* listener, void* user_data);
- void removeInventoryListener(LLVOInventoryListener* listener);
- BOOL isInventoryPending() { return mInventoryPending; }
- void clearInventoryListeners();
- void requestInventory();
- void fetchInventoryFromServer();
- static void processTaskInv(LLMessageSystem* msg, void** user_data);
- void removeInventory(const LLUUID& item_id);
-
- // The updateInventory() call potentially calls into the selection
- // manager, so do no call updateInventory() from the selection
- // manager until we have better iterators.
- void updateInventory(LLViewerInventoryItem* item, U8 key, bool is_new);
- void updateInventoryLocal(LLInventoryItem* item, U8 key); // Update without messaging.
- LLInventoryObject* getInventoryObject(const LLUUID& item_id);
- void getInventoryContents(LLInventoryObject::object_list_t& objects);
- LLInventoryObject* getInventoryRoot();
- LLViewerInventoryItem* getInventoryItemByAsset(const LLUUID& asset_id);
- S16 getInventorySerial() const { return mInventorySerialNum; }
-
- // These functions does viewer-side only object inventory modifications
- void updateViewerInventoryAsset(
- const LLViewerInventoryItem* item,
- const LLUUID& new_asset);
-
- // This function will make sure that we refresh the inventory.
- void dirtyInventory();
- BOOL isInventoryDirty() { return mInventoryDirty; }
-
- // save a script, which involves removing the old one, and rezzing
- // in the new one. This method should be called with the asset id
- // of the new and old script AFTER the bytecode has been saved.
- void saveScript(const LLViewerInventoryItem* item, BOOL active, bool is_new);
-
- // move an inventory item out of the task and into agent
- // inventory. This operation is based on messaging. No permissions
- // checks are made on the viewer - the server will double check.
- void moveInventory(const LLUUID& agent_folder, const LLUUID& item_id);
-
- // Find the number of instances of this object's inventory that are of the given type
- S32 countInventoryContents( LLAssetType::EType type );
-
- BOOL permAnyOwner() const;
- BOOL permYouOwner() const;
- BOOL permGroupOwner() const;
- BOOL permOwnerModify() const;
- BOOL permModify() const;
- BOOL permCopy() const;
- BOOL permMove() const;
- BOOL permTransfer() const;
- inline BOOL usePhysics() const { return ((mFlags & FLAGS_USE_PHYSICS) != 0); }
- inline BOOL flagScripted() const { return ((mFlags & FLAGS_SCRIPTED) != 0); }
- inline BOOL flagHandleTouch() const { return ((mFlags & FLAGS_HANDLE_TOUCH) != 0); }
- inline BOOL flagTakesMoney() const { return ((mFlags & FLAGS_TAKES_MONEY) != 0); }
- inline BOOL flagPhantom() const { return ((mFlags & FLAGS_PHANTOM) != 0); }
- inline BOOL flagInventoryEmpty() const { return ((mFlags & FLAGS_INVENTORY_EMPTY) != 0); }
- inline BOOL flagCastShadows() const { return ((mFlags & FLAGS_CAST_SHADOWS) != 0); }
- inline BOOL flagAllowInventoryAdd() const { return ((mFlags & FLAGS_ALLOW_INVENTORY_DROP) != 0); }
- inline BOOL flagTemporary() const { return ((mFlags & FLAGS_TEMPORARY) != 0); }
- inline BOOL flagTemporaryOnRez() const { return ((mFlags & FLAGS_TEMPORARY_ON_REZ) != 0); }
- inline BOOL flagAnimSource() const { return ((mFlags & FLAGS_ANIM_SOURCE) != 0); }
- inline BOOL flagCameraSource() const { return ((mFlags & FLAGS_CAMERA_SOURCE) != 0); }
- inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); }
- inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); }
-
- U8 getPhysicsShapeType() const;
- inline F32 getPhysicsGravity() const { return mPhysicsGravity; }
- inline F32 getPhysicsFriction() const { return mPhysicsFriction; }
- inline F32 getPhysicsDensity() const { return mPhysicsDensity; }
- inline F32 getPhysicsRestitution() const { return mPhysicsRestitution; }
-
- bool getIncludeInSearch() const;
- void setIncludeInSearch(bool include_in_search);
-
- // Does "open" object menu item apply?
- BOOL allowOpen() const;
-
- void setClickAction(U8 action) { mClickAction = action; }
- U8 getClickAction() const { return mClickAction; }
- bool specialHoverCursor() const; // does it have a special hover cursor?
-
- void setRegion(LLViewerRegion *regionp);
- virtual void updateRegion(LLViewerRegion *regionp);
-
- void updateFlags(BOOL physics_changed = FALSE);
- BOOL setFlags(U32 flag, BOOL state);
- void setPhysicsShapeType(U8 type);
- void setPhysicsGravity(F32 gravity);
- void setPhysicsFriction(F32 friction);
- void setPhysicsDensity(F32 density);
- void setPhysicsRestitution(F32 restitution);
-
- virtual void dump() const;
- static U32 getNumZombieObjects() { return sNumZombieObjects; }
-
- void printNameValuePairs() const;
-
- virtual S32 getLOD() const { return 3; }
- virtual U32 getPartitionType() const;
- virtual void dirtySpatialGroup(BOOL priority = FALSE) const;
- virtual void dirtyMesh();
-
- virtual LLNetworkData* getParameterEntry(U16 param_type) const;
- virtual bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin);
- virtual BOOL getParameterEntryInUse(U16 param_type) const;
- virtual bool setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin);
- // Called when a parameter is changed
- virtual void parameterChanged(U16 param_type, bool local_origin);
- virtual void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin);
-
- friend class LLViewerObjectList;
- friend class LLViewerMediaList;
-
-public:
- //counter-translation
- void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE) ;
- //counter-rotation
- void resetChildrenRotationAndPosition(const std::vector<LLQuaternion>& rotations,
- const std::vector<LLVector3>& positions) ;
- void saveUnselectedChildrenRotation(std::vector<LLQuaternion>& rotations) ;
- void saveUnselectedChildrenPosition(std::vector<LLVector3>& positions) ;
- std::vector<LLVector3> mUnselectedChildrenPositions ;
-
-private:
- ExtraParameter* createNewParameterEntry(U16 param_type);
- ExtraParameter* getExtraParameterEntry(U16 param_type) const;
- ExtraParameter* getExtraParameterEntryCreate(U16 param_type);
- bool unpackParameterEntry(U16 param_type, LLDataPacker *dp);
-
- // This function checks to see if the given media URL has changed its version
- // and the update wasn't due to this agent's last action.
- U32 checkMediaURL(const std::string &media_url);
-
- // Motion prediction between updates
- void interpolateLinearMotion(const F64 & time, const F32 & dt);
-
-public:
- //
- // Viewer-side only types - use the LL_PCODE_APP mask.
- //
- typedef enum e_vo_types
- {
- LL_VO_CLOUDS = LL_PCODE_APP | 0x20,
- LL_VO_SURFACE_PATCH = LL_PCODE_APP | 0x30,
- LL_VO_WL_SKY = LL_PCODE_APP | 0x40,
- LL_VO_SQUARE_TORUS = LL_PCODE_APP | 0x50,
- LL_VO_SKY = LL_PCODE_APP | 0x60,
- LL_VO_VOID_WATER = LL_PCODE_APP | 0x70,
- LL_VO_WATER = LL_PCODE_APP | 0x80,
- LL_VO_GROUND = LL_PCODE_APP | 0x90,
- LL_VO_PART_GROUP = LL_PCODE_APP | 0xa0,
- LL_VO_TRIANGLE_TORUS = LL_PCODE_APP | 0xb0,
- LL_VO_HUD_PART_GROUP = LL_PCODE_APP | 0xc0,
- } EVOType;
-
- typedef enum e_physics_shape_types
- {
- PHYSICS_SHAPE_PRIM = 0,
- PHYSICS_SHAPE_NONE,
- PHYSICS_SHAPE_CONVEX_HULL,
- } EPhysicsShapeType;
-
- LLUUID mID;
-
- // unique within region, not unique across regions
- // Local ID = 0 is not used
- U32 mLocalID;
-
- // Last total CRC received from sim, used for caching
- U32 mTotalCRC;
-
- LLPointer<LLViewerTexture> *mTEImages;
-
- // Selection, picking and rendering variables
- U32 mGLName; // GL "name" used by selection code
- BOOL mbCanSelect; // true if user can select this object by clicking
-
- // Grabbed from UPDATE_FLAGS
- U32 mFlags;
-
- // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties
- U8 mPhysicsShapeType;
- F32 mPhysicsGravity;
- F32 mPhysicsFriction;
- F32 mPhysicsDensity;
- F32 mPhysicsRestitution;
-
-
- // Pipeline classes
- LLPointer<LLDrawable> mDrawable;
-
- // Band-aid to select object after all creation initialization is done
- BOOL mCreateSelected;
-
- // Replace textures with web pages on this object while drawing
- BOOL mRenderMedia;
-
- // In bits
- S32 mBestUpdatePrecision;
-
- // TODO: Make all this stuff private. JC
- LLPointer<LLHUDText> mText;
- LLPointer<LLHUDIcon> mIcon;
-
- static BOOL sUseSharedDrawables;
-
-protected:
- // delete an item in the inventory, but don't tell the
- // server. This is used internally by remove, update, and
- // savescript.
- void deleteInventoryItem(const LLUUID& item_id);
-
- // do the update/caching logic. called by saveScript and
- // updateInventory.
- void doUpdateInventory(LLPointer<LLViewerInventoryItem>& item, U8 key, bool is_new);
-
-
- static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp);
-
- BOOL setData(const U8 *datap, const U32 data_size);
-
- // Hide or show HUD, icon and particles
- void hideExtraDisplayItems( BOOL hidden );
-
- //////////////////////////
- //
- // inventory functionality
- //
-
- static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status);
- void loadTaskInvFile(const std::string& filename);
- void doInventoryCallback();
-
- BOOL isOnMap();
-
- void unpackParticleSource(const S32 block_num, const LLUUID& owner_id);
- void unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id);
- void deleteParticleSource();
- void setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id);
-
-public:
- void updateQuota( const SelectionQuota& quota );
- const SelectionQuota& getQuota( void ) { return mSelectionQuota; }
-
-private:
- void setNameValueList(const std::string& list); // clears nv pairs and then individually adds \n separated NV pairs from \0 terminated string
- void deleteTEImages(); // correctly deletes list of images
-
-protected:
- typedef std::map<char *, LLNameValue *> name_value_map_t;
- name_value_map_t mNameValuePairs; // Any name-value pairs stored by script
-
- child_list_t mChildList;
-
- F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation
- F64 mLastMessageUpdateSecs; // Last update from a message from the simulator
- TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator
-
- // extra data sent from the sim...currently only used for tree species info
- U8* mData;
-
- LLPointer<LLViewerPartSourceScript> mPartSourcep; // Particle source associated with this object.
- LLAudioSourceVO* mAudioSourcep;
- F32 mAudioGain;
-
- F32 mAppAngle; // Apparent visual arc in degrees
- F32 mPixelArea; // Apparent area in pixels
-
- // This is the object's inventory from the viewer's perspective.
- LLInventoryObject::object_list_t* mInventory;
- class LLInventoryCallbackInfo
- {
- public:
- ~LLInventoryCallbackInfo();
- LLVOInventoryListener* mListener;
- void* mInventoryData;
- };
- typedef std::list<LLInventoryCallbackInfo*> callback_list_t;
- callback_list_t mInventoryCallbacks;
- S16 mInventorySerialNum;
-
- LLViewerRegion *mRegionp; // Region that this object belongs to.
- BOOL mInventoryPending;
- BOOL mInventoryDirty;
- BOOL mDead;
- BOOL mOrphaned; // This is an orphaned child
- BOOL mUserSelected; // Cached user select information
- BOOL mOnActiveList;
- BOOL mOnMap; // On the map.
- BOOL mStatic; // Object doesn't move.
- S32 mNumFaces;
-
- F32 mTimeDilation; // Time dilation sent with the object.
- F32 mRotTime; // Amount (in seconds) that object has rotated according to angular velocity (llSetTargetOmega)
- LLQuaternion mLastRot; // last rotation received from the simulator
-
- LLVOJointInfo* mJointInfo;
- U8 mState; // legacy
- LLViewerObjectMedia* mMedia; // NULL if no media associated
- U8 mClickAction;
- F32 mObjectCost; //resource cost of this object or -1 if unknown
- F32 mLinksetCost;
- F32 mPhysicsCost;
- F32 mLinksetPhysicsCost;
-
- SelectionQuota mSelectionQuota;
-
- bool mCostStale;
- mutable bool mPhysicsShapeUnknown;
-
- static U32 sNumZombieObjects; // Objects which are dead, but not deleted
-
- static BOOL sMapDebug; // Map render mode
- static LLColor4 sEditSelectColor;
- static LLColor4 sNoEditSelectColor;
- static F32 sCurrentPulse;
- static BOOL sPulseEnabled;
-
- static S32 sAxisArrowLength;
-
- // These two caches are only correct for non-parented objects right now!
- mutable LLVector3 mPositionRegion;
- mutable LLVector3 mPositionAgent;
-
- static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64) value; }
- static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64) value; }
-
- static void setVelocityInterpolate(BOOL value) { sVelocityInterpolate = value; }
- static void setPingInterpolate(BOOL value) { sPingInterpolate = value; }
-
-private:
- static S32 sNumObjects;
-
- static F64 sPhaseOutUpdateInterpolationTime; // For motion interpolation
- static F64 sMaxUpdateInterpolationTime; // For motion interpolation
-
- static BOOL sVelocityInterpolate;
- static BOOL sPingInterpolate;
-
- //--------------------------------------------------------------------
- // For objects that are attachments
- //--------------------------------------------------------------------
-public:
- const LLUUID &getAttachmentItemID() const;
- void setAttachmentItemID(const LLUUID &id);
- const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object
- EObjectUpdateType getLastUpdateType() const;
- void setLastUpdateType(EObjectUpdateType last_update_type);
- BOOL getLastUpdateCached() const;
- void setLastUpdateCached(BOOL last_update_cached);
-
-private:
- LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory.
- EObjectUpdateType mLastUpdateType;
- BOOL mLastUpdateCached;
-};
-
-///////////////////
-//
-// Inlines
-//
-//
-
-inline void LLViewerObject::setRotation(const LLQuaternion& quat, BOOL damped)
-{
- LLPrimitive::setRotation(quat);
- setChanged(ROTATED | SILHOUETTE);
- updateDrawable(damped);
-}
-
-inline void LLViewerObject::setRotation(const F32 x, const F32 y, const F32 z, BOOL damped)
-{
- LLPrimitive::setRotation(x, y, z);
- setChanged(ROTATED | SILHOUETTE);
- updateDrawable(damped);
-}
-
-class LLViewerObjectMedia
-{
-public:
- LLViewerObjectMedia() : mMediaURL(), mPassedWhitelist(FALSE), mMediaType(0) { }
-
- std::string mMediaURL; // for web pages on surfaces, one per prim
- BOOL mPassedWhitelist; // user has OK'd display
- U8 mMediaType; // see LLTextureEntry::WEB_PAGE, etc.
-};
-
-// subclass of viewer object that can be added to particle partitions
-class LLAlphaObject : public LLViewerObject
-{
-public:
- LLAlphaObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
- : LLViewerObject(id,pcode,regionp)
- { mDepth = 0.f; }
-
- virtual F32 getPartSize(S32 idx);
- virtual void getGeometry(S32 idx,
- LLStrider<LLVector3>& verticesp,
- LLStrider<LLVector3>& normalsp,
- LLStrider<LLVector2>& texcoordsp,
- LLStrider<LLColor4U>& colorsp,
- LLStrider<U16>& indicesp) = 0;
-
- F32 mDepth;
-};
-
-class LLStaticViewerObject : public LLViewerObject
-{
-public:
- LLStaticViewerObject(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp, BOOL is_global = FALSE)
- : LLViewerObject(id,pcode,regionp, is_global)
- { }
-
- virtual void updateDrawable(BOOL force_damped);
-};
-
-
-#endif
+/** + * @file llviewerobject.h + * @brief Description of LLViewerObject class, which is the base class for most objects in the viewer. + * + * $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$ + */ + +#ifndef LL_LLVIEWEROBJECT_H +#define LL_LLVIEWEROBJECT_H + +#include <map> + +#include "llassetstorage.h" +#include "lldarrayptr.h" +#include "llhudicon.h" +#include "llinventory.h" +#include "llrefcount.h" +#include "llmemtype.h" +#include "llprimitive.h" +#include "lluuid.h" +#include "llvoinventorylistener.h" +#include "object_flags.h" +#include "llquaternion.h" +#include "v3dmath.h" +#include "v3math.h" +#include "llvertexbuffer.h" +#include "llaccountingquota.h" + +class LLAgent; // TODO: Get rid of this. +class LLAudioSource; +class LLAudioSourceVO; +class LLBBox; +class LLDataPacker; +class LLColor4; +class LLFrameTimer; +class LLDrawable; +class LLHost; +class LLHUDText; +class LLWorld; +class LLNameValue; +class LLNetMap; +class LLMessageSystem; +class LLPartSysData; +class LLPrimitive; +class LLPipeline; +class LLTextureEntry; +class LLViewerTexture; +class LLViewerInventoryItem; +class LLViewerObject; +class LLViewerPartSourceScript; +class LLViewerRegion; +class LLViewerObjectMedia; +class LLVOInventoryListener; +class LLVOAvatar; + +typedef enum e_object_update_type +{ + OUT_FULL, + OUT_TERSE_IMPROVED, + OUT_FULL_COMPRESSED, + OUT_FULL_CACHED, + OUT_UNKNOWN, +} EObjectUpdateType; + + +// callback typedef for inventory +typedef void (*inventory_callback)(LLViewerObject*, + LLInventoryObject::object_list_t*, + S32 serial_num, + void*); + +// a small struct for keeping track of joints +struct LLVOJointInfo +{ + EHavokJointType mJointType; + LLVector3 mPivot; // parent-frame + // whether the below an axis or anchor (and thus its frame) + // depends on the joint type: + // HINGE ==> axis=parent-frame + // P2P ==> anchor=child-frame + LLVector3 mAxisOrAnchor; +}; + +// for exporting textured materials from SL +struct LLMaterialExportInfo +{ +public: + LLMaterialExportInfo(S32 mat_index, S32 texture_index, LLColor4 color) : + mMaterialIndex(mat_index), mTextureIndex(texture_index), mColor(color) {}; + + S32 mMaterialIndex; + S32 mTextureIndex; + LLColor4 mColor; +}; + +//============================================================================ + +class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate +{ +protected: + ~LLViewerObject(); // use unref() + + // TomY: Provide for a list of extra parameter structures, mapped by structure name + struct ExtraParameter + { + BOOL in_use; + LLNetworkData *data; + }; + std::map<U16, ExtraParameter*> mExtraParameterList; + +public: + typedef std::list<LLPointer<LLViewerObject> > child_list_t; + typedef std::list<LLPointer<LLViewerObject> > vobj_list_t; + + typedef const child_list_t const_child_list_t; + + LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global = FALSE); + MEM_TYPE_NEW(LLMemType::MTYPE_OBJECT); + + virtual void markDead(); // Mark this object as dead, and clean up its references + BOOL isDead() const {return mDead;} + BOOL isOrphaned() const { return mOrphaned; } + BOOL isParticleSource() const; + + virtual LLVOAvatar* asAvatar(); + + static void initVOClasses(); + static void cleanupVOClasses(); + + void addNVPair(const std::string& data); + BOOL removeNVPair(const std::string& name); + LLNameValue* getNVPair(const std::string& name) const; // null if no name value pair by that name + + // Object create and update functions + virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + + // Types of media we can associate + enum { MEDIA_NONE = 0, MEDIA_SET = 1 }; + + // Return codes for processUpdateMessage + enum { + MEDIA_URL_REMOVED = 0x1, + MEDIA_URL_ADDED = 0x2, + MEDIA_URL_UPDATED = 0x4, + MEDIA_FLAGS_CHANGED = 0x8, + INVALID_UPDATE = 0x80000000 + }; + + virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp); + + + virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate. + BOOL onActiveList() const {return mOnActiveList;} + void setOnActiveList(BOOL on_active) { mOnActiveList = on_active; } + + virtual BOOL isAttachment() const { return FALSE; } + virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment + virtual BOOL isHUDAttachment() const { return FALSE; } + virtual void updateRadius() {}; + virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius() + + BOOL isJointChild() const { return mJointInfo ? TRUE : FALSE; } + EHavokJointType getJointType() const { return mJointInfo ? mJointInfo->mJointType : HJT_INVALID; } + // for jointed and other parent-relative hacks + LLViewerObject* getSubParent(); + const LLViewerObject* getSubParent() const; + + // Object visiblility and GPW functions + virtual void setPixelAreaAndAngle(LLAgent &agent); // Override to generate accurate apparent angle and area + + virtual U32 getNumVertices() const; + virtual U32 getNumIndices() const; + S32 getNumFaces() const { return mNumFaces; } + + // Graphical stuff for objects - maybe broken out into render class later? + virtual void updateTextures(); + virtual void boostTexturePriority(BOOL boost_children = TRUE); // When you just want to boost priority of this object + + virtual LLDrawable* createDrawable(LLPipeline *pipeline); + virtual BOOL updateGeometry(LLDrawable *drawable); + virtual void updateGL(); + virtual void updateFaceSize(S32 idx); + virtual BOOL updateLOD(); + virtual BOOL setDrawableParent(LLDrawable* parentp); + F32 getRotTime() { return mRotTime; } + void resetRot(); + void applyAngularVelocity(F32 dt); + + void setLineWidthForWindowSize(S32 window_width); + + static void increaseArrowLength(); // makes axis arrows for selections longer + static void decreaseArrowLength(); // makes axis arrows for selections shorter + + // Accessor functions + LLViewerRegion* getRegion() const { return mRegionp; } + + BOOL isSelected() const { return mUserSelected; } + virtual void setSelected(BOOL sel) { mUserSelected = sel; mRotTime = 0.f;} + + const LLUUID &getID() const { return mID; } + U32 getLocalID() const { return mLocalID; } + U32 getCRC() const { return mTotalCRC; } + + virtual BOOL isFlexible() const { return FALSE; } + virtual BOOL isSculpted() const { return FALSE; } + virtual BOOL isMesh() const { return FALSE; } + virtual BOOL hasLightTexture() const { return FALSE; } + + // This method returns true if the object is over land owned by + // the agent, one of its groups, or it encroaches and + // anti-encroachment is enabled + bool isReturnable(); + + /* + // This method will scan through this object, and then query the + // selection manager to see if the local agent probably has the + // ability to modify the object. Since this calls into the + // selection manager, you should avoid calling this method from + // there. + BOOL isProbablyModifiable() const; + */ + + virtual BOOL setParent(LLViewerObject* parent); + virtual void addChild(LLViewerObject *childp); + virtual void removeChild(LLViewerObject *childp); + const_child_list_t& getChildren() const { return mChildList; } + S32 numChildren() const { return mChildList.size(); } + void addThisAndAllChildren(std::vector<LLViewerObject*>& objects); + void addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects); + BOOL isChild(LLViewerObject *childp) const; + BOOL isSeat() const; + + + //detect if given line segment (in agent space) intersects with this viewer object. + //returns TRUE if intersection detected and returns information about intersection + virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face = -1, // which face to check, -1 = ALL_SIDES + BOOL pick_transparent = FALSE, + S32* face_hit = NULL, // which face was hit + LLVector3* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector3* normal = NULL, // return the surface normal at the intersection point + LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + ); + + virtual BOOL lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end); + + virtual const LLVector3d getPositionGlobal() const; + virtual const LLVector3 &getPositionRegion() const; + virtual const LLVector3 getPositionEdit() const; + virtual const LLVector3 &getPositionAgent() const; + virtual const LLVector3 getRenderPosition() const; + + virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not + + LLViewerObject* getRootEdit() const; + + const LLQuaternion getRotationRegion() const; + const LLQuaternion getRotationEdit() const; + const LLQuaternion getRenderRotation() const; + virtual const LLMatrix4 getRenderMatrix() const; + + void setPosition(const LLVector3 &pos, BOOL damped = FALSE); + void setPositionGlobal(const LLVector3d &position, BOOL damped = FALSE); + void setPositionRegion(const LLVector3 &position, BOOL damped = FALSE); + void setPositionEdit(const LLVector3 &position, BOOL damped = FALSE); + void setPositionAgent(const LLVector3 &pos_agent, BOOL damped = FALSE); + void setPositionParent(const LLVector3 &pos_parent, BOOL damped = FALSE); + void setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped = FALSE ); + + virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const { return xform->getWorldMatrix(); } + + inline void setRotation(const F32 x, const F32 y, const F32 z, BOOL damped = FALSE); + inline void setRotation(const LLQuaternion& quat, BOOL damped = FALSE); + void sendRotationUpdate() const; + + /*virtual*/ void setNumTEs(const U8 num_tes); + /*virtual*/ void setTE(const U8 te, const LLTextureEntry &texture_entry); + /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); + S32 setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host); + /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color); + /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color); + /*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t); + /*virtual*/ S32 setTEScaleS(const U8 te, const F32 s); + /*virtual*/ S32 setTEScaleT(const U8 te, const F32 t); + /*virtual*/ S32 setTEOffset(const U8 te, const F32 s, const F32 t); + /*virtual*/ S32 setTEOffsetS(const U8 te, const F32 s); + /*virtual*/ S32 setTEOffsetT(const U8 te, const F32 t); + /*virtual*/ S32 setTERotation(const U8 te, const F32 r); + /*virtual*/ S32 setTEBumpmap(const U8 te, const U8 bump ); + /*virtual*/ S32 setTETexGen(const U8 te, const U8 texgen ); + /*virtual*/ S32 setTEMediaTexGen(const U8 te, const U8 media ); // *FIXME: this confusingly acts upon a superset of setTETexGen's flags without absorbing its semantics + /*virtual*/ S32 setTEShiny(const U8 te, const U8 shiny ); + /*virtual*/ S32 setTEFullbright(const U8 te, const U8 fullbright ); + /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags ); + /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); + /*virtual*/ BOOL setMaterial(const U8 material); + virtual void setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive + void changeTEImage(S32 index, LLViewerTexture* new_image) ; + LLViewerTexture *getTEImage(const U8 te) const; + + void fitFaceTexture(const U8 face); + void sendTEUpdate() const; // Sends packed representation of all texture entry information + + virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); + + virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL); + virtual U32 getTriangleCount(); + virtual U32 getHighLODTriangleCount(); + + void setObjectCost(F32 cost); + F32 getObjectCost(); + + void setLinksetCost(F32 cost); + F32 getLinksetCost(); + + void setPhysicsCost(F32 cost); + F32 getPhysicsCost(); + + void setLinksetPhysicsCost(F32 cost); + F32 getLinksetPhysicsCost(); + + void sendShapeUpdate(); + + U8 getState() { return mState; } + + F32 getAppAngle() const { return mAppAngle; } + F32 getPixelArea() const { return mPixelArea; } + void setPixelArea(F32 area) { mPixelArea = area; } + F32 getMaxScale() const; + F32 getMidScale() const; + F32 getMinScale() const; + + // Owner id is this object's owner + void setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags); + void adjustAudioGain(const F32 gain); + void clearAttachedSound() { mAudioSourcep = NULL; } + + // Create if necessary + LLAudioSource *getAudioSource(const LLUUID& owner_id); + bool isAudioSource() {return mAudioSourcep != NULL;} + + U8 getMediaType() const; + void setMediaType(U8 media_type); + + std::string getMediaURL() const; + void setMediaURL(const std::string& media_url); + + BOOL getMediaPassedWhitelist() const; + void setMediaPassedWhitelist(BOOL passed); + + void sendMaterialUpdate() const; + + void setCanSelect(BOOL canSelect); + + void setDebugText(const std::string &utf8text); + void setIcon(LLViewerTexture* icon_image); + void clearIcon(); + + void markForUpdate(BOOL priority); + void updateVolume(const LLVolumeParams& volume_params); + virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); + virtual F32 getBinRadius(); + + LLBBox getBoundingBoxAgent() const; + + void updatePositionCaches() const; // Update the global and region position caches from the object (and parent's) xform. + void updateText(); // update text label position + virtual void updateDrawable(BOOL force_damped); // force updates on static objects + + void setDrawableState(U32 state, BOOL recursive = TRUE); + void clearDrawableState(U32 state, BOOL recursive = TRUE); + + // Called when the drawable shifts + virtual void onShift(const LLVector4a &shift_vector) { } + + ////////////////////////////////////// + // + // Inventory methods + // + + // This function is called when someone is interested in a viewer + // object's inventory. The callback is called as soon as the + // viewer object has the inventory stored locally. + void registerInventoryListener(LLVOInventoryListener* listener, void* user_data); + void removeInventoryListener(LLVOInventoryListener* listener); + BOOL isInventoryPending() { return mInventoryPending; } + void clearInventoryListeners(); + void requestInventory(); + void fetchInventoryFromServer(); + static void processTaskInv(LLMessageSystem* msg, void** user_data); + void removeInventory(const LLUUID& item_id); + + // The updateInventory() call potentially calls into the selection + // manager, so do no call updateInventory() from the selection + // manager until we have better iterators. + void updateInventory(LLViewerInventoryItem* item, U8 key, bool is_new); + void updateInventoryLocal(LLInventoryItem* item, U8 key); // Update without messaging. + LLInventoryObject* getInventoryObject(const LLUUID& item_id); + void getInventoryContents(LLInventoryObject::object_list_t& objects); + LLInventoryObject* getInventoryRoot(); + LLViewerInventoryItem* getInventoryItemByAsset(const LLUUID& asset_id); + S16 getInventorySerial() const { return mInventorySerialNum; } + + // These functions does viewer-side only object inventory modifications + void updateViewerInventoryAsset( + const LLViewerInventoryItem* item, + const LLUUID& new_asset); + + // This function will make sure that we refresh the inventory. + void dirtyInventory(); + BOOL isInventoryDirty() { return mInventoryDirty; } + + // save a script, which involves removing the old one, and rezzing + // in the new one. This method should be called with the asset id + // of the new and old script AFTER the bytecode has been saved. + void saveScript(const LLViewerInventoryItem* item, BOOL active, bool is_new); + + // move an inventory item out of the task and into agent + // inventory. This operation is based on messaging. No permissions + // checks are made on the viewer - the server will double check. + void moveInventory(const LLUUID& agent_folder, const LLUUID& item_id); + + // Find the number of instances of this object's inventory that are of the given type + S32 countInventoryContents( LLAssetType::EType type ); + + BOOL permAnyOwner() const; + BOOL permYouOwner() const; + BOOL permGroupOwner() const; + BOOL permOwnerModify() const; + BOOL permModify() const; + BOOL permCopy() const; + BOOL permMove() const; + BOOL permTransfer() const; + inline BOOL usePhysics() const { return ((mFlags & FLAGS_USE_PHYSICS) != 0); } + inline BOOL flagScripted() const { return ((mFlags & FLAGS_SCRIPTED) != 0); } + inline BOOL flagHandleTouch() const { return ((mFlags & FLAGS_HANDLE_TOUCH) != 0); } + inline BOOL flagTakesMoney() const { return ((mFlags & FLAGS_TAKES_MONEY) != 0); } + inline BOOL flagPhantom() const { return ((mFlags & FLAGS_PHANTOM) != 0); } + inline BOOL flagInventoryEmpty() const { return ((mFlags & FLAGS_INVENTORY_EMPTY) != 0); } + inline BOOL flagCastShadows() const { return ((mFlags & FLAGS_CAST_SHADOWS) != 0); } + inline BOOL flagAllowInventoryAdd() const { return ((mFlags & FLAGS_ALLOW_INVENTORY_DROP) != 0); } + inline BOOL flagTemporary() const { return ((mFlags & FLAGS_TEMPORARY) != 0); } + inline BOOL flagTemporaryOnRez() const { return ((mFlags & FLAGS_TEMPORARY_ON_REZ) != 0); } + inline BOOL flagAnimSource() const { return ((mFlags & FLAGS_ANIM_SOURCE) != 0); } + inline BOOL flagCameraSource() const { return ((mFlags & FLAGS_CAMERA_SOURCE) != 0); } + inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); } + inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); } + + U8 getPhysicsShapeType() const; + inline F32 getPhysicsGravity() const { return mPhysicsGravity; } + inline F32 getPhysicsFriction() const { return mPhysicsFriction; } + inline F32 getPhysicsDensity() const { return mPhysicsDensity; } + inline F32 getPhysicsRestitution() const { return mPhysicsRestitution; } + + bool getIncludeInSearch() const; + void setIncludeInSearch(bool include_in_search); + + // Does "open" object menu item apply? + BOOL allowOpen() const; + + void setClickAction(U8 action) { mClickAction = action; } + U8 getClickAction() const { return mClickAction; } + bool specialHoverCursor() const; // does it have a special hover cursor? + + void setRegion(LLViewerRegion *regionp); + virtual void updateRegion(LLViewerRegion *regionp); + + void updateFlags(BOOL physics_changed = FALSE); + BOOL setFlags(U32 flag, BOOL state); + void setPhysicsShapeType(U8 type); + void setPhysicsGravity(F32 gravity); + void setPhysicsFriction(F32 friction); + void setPhysicsDensity(F32 density); + void setPhysicsRestitution(F32 restitution); + + virtual void dump() const; + static U32 getNumZombieObjects() { return sNumZombieObjects; } + + void printNameValuePairs() const; + + virtual S32 getLOD() const { return 3; } + virtual U32 getPartitionType() const; + virtual void dirtySpatialGroup(BOOL priority = FALSE) const; + virtual void dirtyMesh(); + + virtual LLNetworkData* getParameterEntry(U16 param_type) const; + virtual bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin); + virtual BOOL getParameterEntryInUse(U16 param_type) const; + virtual bool setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin); + // Called when a parameter is changed + virtual void parameterChanged(U16 param_type, bool local_origin); + virtual void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin); + + friend class LLViewerObjectList; + friend class LLViewerMediaList; + +public: + //counter-translation + void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE) ; + //counter-rotation + void resetChildrenRotationAndPosition(const std::vector<LLQuaternion>& rotations, + const std::vector<LLVector3>& positions) ; + void saveUnselectedChildrenRotation(std::vector<LLQuaternion>& rotations) ; + void saveUnselectedChildrenPosition(std::vector<LLVector3>& positions) ; + std::vector<LLVector3> mUnselectedChildrenPositions ; + +private: + ExtraParameter* createNewParameterEntry(U16 param_type); + ExtraParameter* getExtraParameterEntry(U16 param_type) const; + ExtraParameter* getExtraParameterEntryCreate(U16 param_type); + bool unpackParameterEntry(U16 param_type, LLDataPacker *dp); + + // This function checks to see if the given media URL has changed its version + // and the update wasn't due to this agent's last action. + U32 checkMediaURL(const std::string &media_url); + + // Motion prediction between updates + void interpolateLinearMotion(const F64 & time, const F32 & dt); + +public: + // + // Viewer-side only types - use the LL_PCODE_APP mask. + // + typedef enum e_vo_types + { + LL_VO_CLOUDS = LL_PCODE_APP | 0x20, + LL_VO_SURFACE_PATCH = LL_PCODE_APP | 0x30, + LL_VO_WL_SKY = LL_PCODE_APP | 0x40, + LL_VO_SQUARE_TORUS = LL_PCODE_APP | 0x50, + LL_VO_SKY = LL_PCODE_APP | 0x60, + LL_VO_VOID_WATER = LL_PCODE_APP | 0x70, + LL_VO_WATER = LL_PCODE_APP | 0x80, + LL_VO_GROUND = LL_PCODE_APP | 0x90, + LL_VO_PART_GROUP = LL_PCODE_APP | 0xa0, + LL_VO_TRIANGLE_TORUS = LL_PCODE_APP | 0xb0, + LL_VO_HUD_PART_GROUP = LL_PCODE_APP | 0xc0, + } EVOType; + + typedef enum e_physics_shape_types + { + PHYSICS_SHAPE_PRIM = 0, + PHYSICS_SHAPE_NONE, + PHYSICS_SHAPE_CONVEX_HULL, + } EPhysicsShapeType; + + LLUUID mID; + + // unique within region, not unique across regions + // Local ID = 0 is not used + U32 mLocalID; + + // Last total CRC received from sim, used for caching + U32 mTotalCRC; + + LLPointer<LLViewerTexture> *mTEImages; + + // Selection, picking and rendering variables + U32 mGLName; // GL "name" used by selection code + BOOL mbCanSelect; // true if user can select this object by clicking + + // Grabbed from UPDATE_FLAGS + U32 mFlags; + + // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties + U8 mPhysicsShapeType; + F32 mPhysicsGravity; + F32 mPhysicsFriction; + F32 mPhysicsDensity; + F32 mPhysicsRestitution; + + + // Pipeline classes + LLPointer<LLDrawable> mDrawable; + + // Band-aid to select object after all creation initialization is done + BOOL mCreateSelected; + + // Replace textures with web pages on this object while drawing + BOOL mRenderMedia; + + // In bits + S32 mBestUpdatePrecision; + + // TODO: Make all this stuff private. JC + LLPointer<LLHUDText> mText; + LLPointer<LLHUDIcon> mIcon; + + static BOOL sUseSharedDrawables; + +protected: + // delete an item in the inventory, but don't tell the + // server. This is used internally by remove, update, and + // savescript. + void deleteInventoryItem(const LLUUID& item_id); + + // do the update/caching logic. called by saveScript and + // updateInventory. + void doUpdateInventory(LLPointer<LLViewerInventoryItem>& item, U8 key, bool is_new); + + + static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp); + + BOOL setData(const U8 *datap, const U32 data_size); + + // Hide or show HUD, icon and particles + void hideExtraDisplayItems( BOOL hidden ); + + ////////////////////////// + // + // inventory functionality + // + + static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status); + void loadTaskInvFile(const std::string& filename); + void doInventoryCallback(); + + BOOL isOnMap(); + + void unpackParticleSource(const S32 block_num, const LLUUID& owner_id); + void unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id); + void deleteParticleSource(); + void setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id); + +public: + void updateQuota( const SelectionQuota& quota ); + const SelectionQuota& getQuota( void ) { return mSelectionQuota; } + +private: + void setNameValueList(const std::string& list); // clears nv pairs and then individually adds \n separated NV pairs from \0 terminated string + void deleteTEImages(); // correctly deletes list of images + +protected: + typedef std::map<char *, LLNameValue *> name_value_map_t; + name_value_map_t mNameValuePairs; // Any name-value pairs stored by script + + child_list_t mChildList; + + F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation + F64 mLastMessageUpdateSecs; // Last update from a message from the simulator + TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator + + // extra data sent from the sim...currently only used for tree species info + U8* mData; + + LLPointer<LLViewerPartSourceScript> mPartSourcep; // Particle source associated with this object. + LLAudioSourceVO* mAudioSourcep; + F32 mAudioGain; + + F32 mAppAngle; // Apparent visual arc in degrees + F32 mPixelArea; // Apparent area in pixels + + // This is the object's inventory from the viewer's perspective. + LLInventoryObject::object_list_t* mInventory; + class LLInventoryCallbackInfo + { + public: + ~LLInventoryCallbackInfo(); + LLVOInventoryListener* mListener; + void* mInventoryData; + }; + typedef std::list<LLInventoryCallbackInfo*> callback_list_t; + callback_list_t mInventoryCallbacks; + S16 mInventorySerialNum; + + LLViewerRegion *mRegionp; // Region that this object belongs to. + BOOL mInventoryPending; + BOOL mInventoryDirty; + BOOL mDead; + BOOL mOrphaned; // This is an orphaned child + BOOL mUserSelected; // Cached user select information + BOOL mOnActiveList; + BOOL mOnMap; // On the map. + BOOL mStatic; // Object doesn't move. + S32 mNumFaces; + + F32 mTimeDilation; // Time dilation sent with the object. + F32 mRotTime; // Amount (in seconds) that object has rotated according to angular velocity (llSetTargetOmega) + LLQuaternion mLastRot; // last rotation received from the simulator + + LLVOJointInfo* mJointInfo; + U8 mState; // legacy + LLViewerObjectMedia* mMedia; // NULL if no media associated + U8 mClickAction; + F32 mObjectCost; //resource cost of this object or -1 if unknown + F32 mLinksetCost; + F32 mPhysicsCost; + F32 mLinksetPhysicsCost; + + SelectionQuota mSelectionQuota; + + bool mCostStale; + mutable bool mPhysicsShapeUnknown; + + static U32 sNumZombieObjects; // Objects which are dead, but not deleted + + static BOOL sMapDebug; // Map render mode + static LLColor4 sEditSelectColor; + static LLColor4 sNoEditSelectColor; + static F32 sCurrentPulse; + static BOOL sPulseEnabled; + + static S32 sAxisArrowLength; + + // These two caches are only correct for non-parented objects right now! + mutable LLVector3 mPositionRegion; + mutable LLVector3 mPositionAgent; + + static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64) value; } + static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64) value; } + + static void setVelocityInterpolate(BOOL value) { sVelocityInterpolate = value; } + static void setPingInterpolate(BOOL value) { sPingInterpolate = value; } + +private: + static S32 sNumObjects; + + static F64 sPhaseOutUpdateInterpolationTime; // For motion interpolation + static F64 sMaxUpdateInterpolationTime; // For motion interpolation + + static BOOL sVelocityInterpolate; + static BOOL sPingInterpolate; + + //-------------------------------------------------------------------- + // For objects that are attachments + //-------------------------------------------------------------------- +public: + const LLUUID &getAttachmentItemID() const; + void setAttachmentItemID(const LLUUID &id); + const LLUUID &extractAttachmentItemID(); // find&set the inventory item ID of the attached object + EObjectUpdateType getLastUpdateType() const; + void setLastUpdateType(EObjectUpdateType last_update_type); + BOOL getLastUpdateCached() const; + void setLastUpdateCached(BOOL last_update_cached); + +private: + LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory. + EObjectUpdateType mLastUpdateType; + BOOL mLastUpdateCached; +}; + +/////////////////// +// +// Inlines +// +// + +inline void LLViewerObject::setRotation(const LLQuaternion& quat, BOOL damped) +{ + LLPrimitive::setRotation(quat); + setChanged(ROTATED | SILHOUETTE); + updateDrawable(damped); +} + +inline void LLViewerObject::setRotation(const F32 x, const F32 y, const F32 z, BOOL damped) +{ + LLPrimitive::setRotation(x, y, z); + setChanged(ROTATED | SILHOUETTE); + updateDrawable(damped); +} + +class LLViewerObjectMedia +{ +public: + LLViewerObjectMedia() : mMediaURL(), mPassedWhitelist(FALSE), mMediaType(0) { } + + std::string mMediaURL; // for web pages on surfaces, one per prim + BOOL mPassedWhitelist; // user has OK'd display + U8 mMediaType; // see LLTextureEntry::WEB_PAGE, etc. +}; + +// subclass of viewer object that can be added to particle partitions +class LLAlphaObject : public LLViewerObject +{ +public: + LLAlphaObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) + : LLViewerObject(id,pcode,regionp) + { mDepth = 0.f; } + + virtual F32 getPartSize(S32 idx); + virtual void getGeometry(S32 idx, + LLStrider<LLVector3>& verticesp, + LLStrider<LLVector3>& normalsp, + LLStrider<LLVector2>& texcoordsp, + LLStrider<LLColor4U>& colorsp, + LLStrider<U16>& indicesp) = 0; + + F32 mDepth; +}; + +class LLStaticViewerObject : public LLViewerObject +{ +public: + LLStaticViewerObject(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp, BOOL is_global = FALSE) + : LLViewerObject(id,pcode,regionp, is_global) + { } + + virtual void updateDrawable(BOOL force_damped); +}; + + +#endif diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 5ae4e872f3..8db72da1ee 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -2202,9 +2202,9 @@ bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const = parcelOwner == (forGroup ? gAgent.getGroupID() : gAgent.getID()); bool isAuthorized - = (authorizeBuyer.isNull()
- || (gAgent.getID() == authorizeBuyer)
- || (gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_DEED)
+ = (authorizeBuyer.isNull() + || (gAgent.getID() == authorizeBuyer) + || (gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_DEED) && gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_SET_SALE_INFO))); return isForSale && !isOwner && isAuthorized && isEmpowered; diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index 45c9b3e91f..faa86d43dd 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -118,8 +118,8 @@ // Library includes from llvfs #include "lldir.h" -
-// Library includes from llmessage project
+ +// Library includes from llmessage project #include "llcachename.h" #endif diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index d9ff931575..cd6653b0c7 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -110,8 +110,8 @@ void LLViewerTextureList::doPreloadImages() { LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL; - llassert_always(mInitialized) ;
- llassert_always(mImageList.empty()) ;
+ llassert_always(mInitialized) ; + llassert_always(mImageList.empty()) ; llassert_always(mUUIDMap.empty()) ; // Set the "missing asset" image |