From 781af27e9cd500f6d62bc2d4658180f154af8816 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 9 May 2011 13:49:20 -0400 Subject: SH-1419 Sim complains about changing physical materials when Physics, Temporary, or Phantom is changed. --- indra/newview/llselectmgr.cpp | 10 +++++----- indra/newview/llviewerobject.cpp | 17 ++++++++++------- indra/newview/llviewerobject.h | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'indra') diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 9b264b81c7..8fa4065fa6 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1997,7 +1997,7 @@ void LLSelectMgr::selectionSetPhysicsType(U8 type) if (object->permModify()) { object->setPhysicsShapeType(mType); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2016,7 +2016,7 @@ void LLSelectMgr::selectionSetFriction(F32 friction) if (object->permModify()) { object->setPhysicsFriction(mFriction); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2035,7 +2035,7 @@ void LLSelectMgr::selectionSetGravity(F32 gravity ) if (object->permModify()) { object->setPhysicsGravity(mGravity); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2054,7 +2054,7 @@ void LLSelectMgr::selectionSetDensity(F32 density ) if (object->permModify()) { object->setPhysicsDensity(mDensity); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2073,7 +2073,7 @@ void LLSelectMgr::selectionSetRestitution(F32 restitution) if (object->permModify()) { object->setPhysicsRestitution(mRestitution); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 6d493bfcd5..f5fee662e6 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5282,7 +5282,7 @@ bool LLViewerObject::specialHoverCursor() const || (mClickAction != 0); } -void LLViewerObject::updateFlags() +void LLViewerObject::updateFlags(BOOL physics_changed) { LLViewerRegion* regionp = getRegion(); if(!regionp) return; @@ -5295,12 +5295,15 @@ void LLViewerObject::updateFlags() gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); - gMessageSystem->nextBlock("ExtraPhysics"); - gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() ); - gMessageSystem->addF32("Density", getPhysicsDensity() ); - gMessageSystem->addF32("Friction", getPhysicsFriction() ); - gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); - gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); + 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() ); } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index e417343bec..21198f7dd1 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -488,7 +488,7 @@ public: void setRegion(LLViewerRegion *regionp); virtual void updateRegion(LLViewerRegion *regionp); - void updateFlags(); + void updateFlags(BOOL physics_changed = FALSE); BOOL setFlags(U32 flag, BOOL state); void setPhysicsShapeType(U8 type); void setPhysicsGravity(F32 gravity); -- cgit v1.2.3 From 155d96000fdb319ee9ce03fd2e2d94c08f0c0a21 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 9 May 2011 13:50:07 -0400 Subject: SH-1444 "Allow mesh objects" setting is visible on a non-mesh region. --- indra/newview/llfloaterregioninfo.cpp | 5 +++++ indra/newview/skins/default/xui/en/panel_region_general.xml | 1 + 2 files changed, 6 insertions(+) (limited to 'indra') diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 34fda49375..fc6976755f 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -590,6 +590,11 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) getChildView("im_btn")->setEnabled(allow_modify); getChildView("manage_telehub_btn")->setEnabled(allow_modify); + const bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + gAgent.getRegion() && + !gAgent.getRegion()->getCapability("GetMesh").empty(); + getChildView("mesh_rez_enabled_check")->setVisible(enable_mesh); + getChildView("mesh_rez_enabled_check")->setEnabled(getChildView("mesh_rez_enabled_check")->getEnabled() && enable_mesh); // Data gets filled in by processRegionInfo return LLPanelRegionInfo::refreshFromRegion(region); diff --git a/indra/newview/skins/default/xui/en/panel_region_general.xml b/indra/newview/skins/default/xui/en/panel_region_general.xml index e0d9f3f714..3f9195d092 100644 --- a/indra/newview/skins/default/xui/en/panel_region_general.xml +++ b/indra/newview/skins/default/xui/en/panel_region_general.xml @@ -134,6 +134,7 @@ top="190" width="80" /> Date: Mon, 9 May 2011 18:00:10 -0400 Subject: SH-1343 Change wizard slider labels Changed "Performance" and "Accuracy" to "Higher Performance" and "Higher Accuracy" on physics page. --- indra/newview/skins/default/xui/en/floater_model_wizard.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml index 03af348a8d..fa4c56ffec 100644 --- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml +++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml @@ -571,9 +571,9 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se bg_opaque_color="DkGray2" background_visible="true" background_opaque="true"> - Performance + Higher Performance Faster rendering but less detailed; lowers Resource (prim) cost. - Accuracy + Higher Accuracy More detailed model but slower; increases Resource (prim) cost. Date: Fri, 13 May 2011 15:56:38 -0400 Subject: SH-769 FIXED Name field in upload model dialog allows 255 characters --- indra/newview/skins/default/xui/en/floater_model_preview.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index d08c3e7078..533e0c96f2 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -26,7 +26,7 @@ Name: - -- cgit v1.2.3 From b1453b1584788de8ba9be0b2d549ac8450669632 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 16 May 2011 12:34:25 -0400 Subject: SH-1506 "Upload Wizard" is missing from Inventory's add menu --- indra/newview/skins/default/xui/en/menu_inventory_add.xml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index 484af63097..b36b82ebd8 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -42,7 +42,7 @@ - @@ -54,6 +54,18 @@ + + + + + Date: Mon, 16 May 2011 12:56:18 -0400 Subject: sh-1491 WIP --- indra/newview/llfirstuse.cpp | 2 +- indra/newview/llmeshrepository.cpp | 43 +++++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index 2c4153688a..a9f52282a5 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -131,7 +131,7 @@ void LLFirstUse::notMoving(bool enable) // static void LLFirstUse::viewPopup(bool enable) { - firstUseNotification("FirstViewPopup", enable, "HintView", LLSD(), LLSD().with("target", "view_popup").with("direction", "right")); +// firstUseNotification("FirstViewPopup", enable, "HintView", LLSD(), LLSD().with("target", "view_popup").with("direction", "right")); } // static diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 2a68fbac8d..653fb46754 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -84,6 +84,8 @@ U32 LLMeshRepository::sPeakKbps = 0; const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5; +void dumpLLSDToFile(LLSD& content, std::string filename); + std::string header_lod[] = { "lowest_lod", @@ -492,11 +494,18 @@ public: const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - assert_main_thread(); + //assert_main_thread(); llinfos << "completed" << llendl; mThread->mPendingUploads--; + + LLSD content; + LLBufferStream istr(channels, buffer.get()); + if (!LLSDSerialize::fromXML(content, istr)) + { + llinfos << "Failed to deserialize LLSD. " << " [" << status << "]: " << reason << llendl; + } + dumpLLSDToFile(content,"whole_model_response.xml"); } - }; LLMeshRepoThread::LLMeshRepoThread() @@ -1362,8 +1371,8 @@ void LLMeshUploadThread::run() } } -#if 0 -void dumpLLSDToFile(LLSD& content, std::string& filename) +#if 1 +void dumpLLSDToFile(LLSD& content, std::string filename) { std::ofstream of(filename); LLSDSerialize::toPrettyXML(content,of); @@ -1373,9 +1382,10 @@ void dumpLLSDToFile(LLSD& content, std::string& filename) void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) { // TODO where do textures go? - + LLSD result; + LLSD res; result["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); result["asset_type"] = "mesh"; result["inventory_type"] = "object"; @@ -1384,9 +1394,9 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) // TODO "optional" fields from the spec - LLSD res; res["mesh_list"] = LLSD::emptyArray(); - res["texture_list"] = LLSD::emptyArray(); +// TODO Textures + //res["texture_list"] = LLSD::emptyArray(); S32 mesh_num = 0; S32 texture_num = 0; @@ -1432,10 +1442,15 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) LLQuaternion rot; LLMatrix4 transformation = instance.mTransform; decomposeMeshMatrix(transformation,pos,rot,scale); - + +#if 0 mesh_entry["childpos"] = ll_sd_from_vector3(pos); mesh_entry["childrot"] = ll_sd_from_quaternion(rot); mesh_entry["scale"] = ll_sd_from_vector3(scale); +#endif + mesh_entry["position"] = ll_sd_from_vector3(LLVector3()); + mesh_entry["rotation"] = ll_sd_from_quaternion(rot); + mesh_entry["scale"] = ll_sd_from_vector3(scale); // TODO should be binary. std::string str = ostr.str(); @@ -1479,9 +1494,8 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) } result["asset_resources"] = res; -#if 0 - std::string name("whole_model.xml"); - dumpLLSDToFile(result,name); +#if 1 + dumpLLSDToFile(result,"whole_model.xml"); #endif dest = result; @@ -1540,9 +1554,14 @@ void LLMeshUploadThread::doWholeModelUpload() mPendingUploads++; LLCurlRequest::headers_t headers; - mCurlRequest->post(mWholeModelUploadCapability, headers, model_data.asString(), + mCurlRequest->post(mWholeModelUploadCapability, headers, model_data, new LLWholeModelFeeResponder(this)); + do + { + mCurlRequest->process(); + } while (mCurlRequest->getQueued() > 0); + // Currently a no-op. mFinished = true; } -- cgit v1.2.3 From e088eb82cf94872cd0dc5a673f0c0a3b3bda0703 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 16 May 2011 13:33:44 -0400 Subject: SH-1351 FIXED On the Edit Panel, remove the Override Material checkbox --- indra/newview/llpanelvolume.cpp | 1 - indra/newview/skins/default/xui/en/floater_tools.xml | 10 ---------- 2 files changed, 11 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index c443814c89..ff72ad0c14 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -467,7 +467,6 @@ void LLPanelVolume::refresh() getChildView("label physicsshapetype")->setVisible(enable_mesh); getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh); getChildView("Physics Gravity")->setVisible(enable_mesh); - getChildView("Physics Material Override")->setVisible(enable_mesh); getChildView("Physics Friction")->setVisible(enable_mesh); getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 380eeae403..9178e30c8b 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2441,16 +2441,6 @@ even though the user gets a free copy. top_pad="10" width="132" /> - - Date: Mon, 16 May 2011 15:45:14 -0400 Subject: SH-1352 Move Material dropdown to Features tab, above Physics settings --- indra/newview/llpanelobject.cpp | 88 -------------------- indra/newview/llpanelobject.h | 5 -- indra/newview/llpanelvolume.cpp | 93 +++++++++++++++++++++- indra/newview/llpanelvolume.h | 6 +- .../newview/skins/default/xui/en/floater_tools.xml | 70 ++++++++-------- 5 files changed, 132 insertions(+), 130 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 64af6c2157..204c146f3c 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -33,11 +33,9 @@ #include "lleconomy.h" #include "llerror.h" #include "llfontgl.h" -#include "llmaterialtable.h" #include "llpermissionsflags.h" #include "llstring.h" #include "llvolume.h" -#include "material_codes.h" #include "m3math.h" // project includes @@ -57,7 +55,6 @@ #include "lltool.h" #include "lltoolcomp.h" #include "lltoolmgr.h" -#include "lltrans.h" #include "llui.h" #include "llviewerobject.h" #include "llviewerregion.h" @@ -101,17 +98,6 @@ BOOL LLPanelObject::postBuild() { setMouseOpaque(FALSE); - std::map material_name_map; - material_name_map["Stone"]= LLTrans::getString("Stone"); - material_name_map["Metal"]= LLTrans::getString("Metal"); - material_name_map["Glass"]= LLTrans::getString("Glass"); - material_name_map["Wood"]= LLTrans::getString("Wood"); - material_name_map["Flesh"]= LLTrans::getString("Flesh"); - material_name_map["Plastic"]= LLTrans::getString("Plastic"); - material_name_map["Rubber"]= LLTrans::getString("Rubber"); - material_name_map["Light"]= LLTrans::getString("Light"); - - LLMaterialTable::basic.initTableTransNames(material_name_map); //-------------------------------------------------------- // Top //-------------------------------------------------------- @@ -166,22 +152,6 @@ BOOL LLPanelObject::postBuild() //-------------------------------------------------------- - // material type popup - mComboMaterial = getChild("material"); - childSetCommitCallback("material",onCommitMaterial,this); - mComboMaterial->removeall(); - - for (LLMaterialTable::info_list_t::iterator iter = LLMaterialTable::basic.mMaterialInfoList.begin(); - iter != LLMaterialTable::basic.mMaterialInfoList.end(); ++iter) - { - LLMaterialInfo* minfop = *iter; - if (minfop->mMCode != LL_MCODE_LIGHT) - { - mComboMaterial->add(minfop->mName); - } - } - mComboMaterialItemCount = mComboMaterial->getItemCount(); - // Base Type mComboBaseType = getChild("comboBaseType"); childSetCommitCallback("comboBaseType",onCommitParametric,this); @@ -309,7 +279,6 @@ BOOL LLPanelObject::postBuild() LLPanelObject::LLPanelObject() : LLPanel(), - mComboMaterialItemCount(0), mIsPhysical(FALSE), mIsTemporary(FALSE), mIsPhantom(FALSE), @@ -527,43 +496,6 @@ void LLPanelObject::getState( ) mCheckCastShadows->setEnabled( roots_selected==1 && editable ); #endif - // Update material part - // slightly inefficient - materials are unique per object, not per TE - U8 material_code = 0; - struct f : public LLSelectedTEGetFunctor - { - U8 get(LLViewerObject* object, S32 te) - { - return object->getMaterial(); - } - } func; - bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); - std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); - if (editable && single_volume && material_same) - { - mComboMaterial->setEnabled( TRUE ); - if (material_code == LL_MCODE_LIGHT) - { - if (mComboMaterial->getItemCount() == mComboMaterialItemCount) - { - mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); - } - mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); - } - else - { - if (mComboMaterial->getItemCount() != mComboMaterialItemCount) - { - mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); - } - - mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); - } - } - else - { - mComboMaterial->setEnabled( FALSE ); - } //---------------------------------------------------------------------------- S32 selected_item = MI_BOX; @@ -1244,25 +1176,6 @@ void LLPanelObject::sendCastShadows() } } -// static -void LLPanelObject::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) -{ - //LLPanelObject* self = (LLPanelObject*) userdata; - LLComboBox* box = (LLComboBox*) ctrl; - - if (box) - { - // apply the currently selected material to the object - const std::string& material_name = box->getSimple(); - std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); - if (material_name != LEGACY_FULLBRIGHT_DESC) - { - U8 material_code = LLMaterialTable::basic.getMCode(material_name); - LLSelectMgr::getInstance()->selectionSetMaterial(material_code); - } - } -} - // static void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) { @@ -1937,7 +1850,6 @@ void LLPanelObject::clearCtrls() mCheckCastShadows->set(FALSE); mCheckCastShadows->setEnabled( FALSE ); #endif - mComboMaterial ->setEnabled( FALSE ); // Disable text labels mLabelPosition ->setEnabled( FALSE ); mLabelSize ->setEnabled( FALSE ); diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index e2f2a4400d..475dfdaedb 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -66,7 +66,6 @@ public: static void onCommitPhantom( LLUICtrl* ctrl, void* userdata); static void onCommitCastShadows( LLUICtrl* ctrl, void* userdata); static void onCommitPhysics( LLUICtrl* ctrl, void* userdata); - static void onCommitMaterial( LLUICtrl* ctrl, void* userdata); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -94,10 +93,6 @@ protected: void getVolumeParams(LLVolumeParams& volume_params); protected: - S32 mComboMaterialItemCount; - - LLComboBox* mComboMaterial; - // Per-object options LLComboBox* mComboBaseType; diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index ff72ad0c14..ebddaa90bc 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -59,6 +59,7 @@ #include "lltool.h" #include "lltoolcomp.h" #include "lltoolmgr.h" +#include "lltrans.h" #include "llui.h" #include "llviewerobject.h" #include "llviewerregion.h" @@ -156,6 +157,34 @@ BOOL LLPanelVolume::postBuild() mSpinPhysicsRestitution = getChild("Physics Restitution"); mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution)); } + + std::map material_name_map; + material_name_map["Stone"]= LLTrans::getString("Stone"); + material_name_map["Metal"]= LLTrans::getString("Metal"); + material_name_map["Glass"]= LLTrans::getString("Glass"); + material_name_map["Wood"]= LLTrans::getString("Wood"); + material_name_map["Flesh"]= LLTrans::getString("Flesh"); + material_name_map["Plastic"]= LLTrans::getString("Plastic"); + material_name_map["Rubber"]= LLTrans::getString("Rubber"); + material_name_map["Light"]= LLTrans::getString("Light"); + + LLMaterialTable::basic.initTableTransNames(material_name_map); + + // material type popup + mComboMaterial = getChild("material"); + childSetCommitCallback("material",onCommitMaterial,this); + mComboMaterial->removeall(); + + for (LLMaterialTable::info_list_t::iterator iter = LLMaterialTable::basic.mMaterialInfoList.begin(); + iter != LLMaterialTable::basic.mMaterialInfoList.end(); ++iter) + { + LLMaterialInfo* minfop = *iter; + if (minfop->mMCode != LL_MCODE_LIGHT) + { + mComboMaterial->add(minfop->mName); + } + } + mComboMaterialItemCount = mComboMaterial->getItemCount(); // Start with everyone disabled clearCtrls(); @@ -164,7 +193,8 @@ BOOL LLPanelVolume::postBuild() } LLPanelVolume::LLPanelVolume() - : LLPanel() + : LLPanel(), + mComboMaterialItemCount(0) { setMouseOpaque(FALSE); @@ -379,6 +409,46 @@ void LLPanelVolume::getState( ) getChildView("FlexForceZ")->setEnabled(false); } + // Material properties + + // Update material part + // slightly inefficient - materials are unique per object, not per TE + U8 material_code = 0; + struct f : public LLSelectedTEGetFunctor + { + U8 get(LLViewerObject* object, S32 te) + { + return object->getMaterial(); + } + } func; + bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); + std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); + if (editable && single_volume && material_same) + { + mComboMaterial->setEnabled( TRUE ); + if (material_code == LL_MCODE_LIGHT) + { + if (mComboMaterial->getItemCount() == mComboMaterialItemCount) + { + mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); + } + mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); + } + else + { + if (mComboMaterial->getItemCount() != mComboMaterialItemCount) + { + mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); + } + + mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); + } + } + else + { + mComboMaterial->setEnabled( FALSE ); + } + // Physics properties mSpinPhysicsGravity->set(objectp->getPhysicsGravity()); @@ -521,6 +591,8 @@ void LLPanelVolume::clearCtrls() mSpinPhysicsFriction->setEnabled(FALSE); mSpinPhysicsDensity->setEnabled(FALSE); mSpinPhysicsRestitution->setEnabled(FALSE); + + mComboMaterial->setEnabled( FALSE ); } // @@ -672,6 +744,25 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) } } +// static +void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) +{ + //LLPanelObject* self = (LLPanelObject*) userdata; + LLComboBox* box = (LLComboBox*) ctrl; + + if (box) + { + // apply the currently selected material to the object + const std::string& material_name = box->getSimple(); + std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); + if (material_name != LEGACY_FULLBRIGHT_DESC) + { + U8 material_code = LLMaterialTable::basic.getMCode(material_name); + LLSelectMgr::getInstance()->selectionSetMaterial(material_code); + } + } +} + // static void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) { diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 776a2c1f4a..0ef47db0d9 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -63,8 +63,8 @@ public: static void onCommitLight( LLUICtrl* ctrl, void* userdata); static void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata); static void onCommitFlexible( LLUICtrl* ctrl, void* userdata); - static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata); + static void onCommitMaterial( LLUICtrl* ctrl, void* userdata); void onLightCancelColor(const LLSD& data); void onLightSelectColor(const LLSD& data); @@ -104,6 +104,10 @@ protected: LLSpinCtrl* mSpinForce[3]; */ + S32 mComboMaterialItemCount; + LLComboBox* mComboMaterial; + + LLColor4 mLightSavedColor; LLUUID mLightSavedTexture; LLPointer mObject; diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 9178e30c8b..501e93ead3 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1608,41 +1608,6 @@ even though the user gets a free copy. name="Sculpted" value="Sculpted" /> - - - - - - - - - + + + + + + + + + Date: Mon, 16 May 2011 17:39:42 -0400 Subject: sh-1491 WIP --- indra/newview/llmeshrepository.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'indra') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 653fb46754..7d48416292 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -84,7 +84,7 @@ U32 LLMeshRepository::sPeakKbps = 0; const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5; -void dumpLLSDToFile(LLSD& content, std::string filename); +void dumpLLSDToFile(const LLSD& content, std::string filename); std::string header_lod[] = { @@ -490,20 +490,13 @@ public: mThread(thread) { } - virtual void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + virtual void completed(U32 status, + const std::string& reason, + const LLSD& content) { //assert_main_thread(); llinfos << "completed" << llendl; mThread->mPendingUploads--; - - LLSD content; - LLBufferStream istr(channels, buffer.get()); - if (!LLSDSerialize::fromXML(content, istr)) - { - llinfos << "Failed to deserialize LLSD. " << " [" << status << "]: " << reason << llendl; - } dumpLLSDToFile(content,"whole_model_response.xml"); } }; @@ -1372,7 +1365,7 @@ void LLMeshUploadThread::run() } #if 1 -void dumpLLSDToFile(LLSD& content, std::string filename) +void dumpLLSDToFile(const LLSD& content, std::string filename) { std::ofstream of(filename); LLSDSerialize::toPrettyXML(content,of); @@ -1562,6 +1555,9 @@ void LLMeshUploadThread::doWholeModelUpload() mCurlRequest->process(); } while (mCurlRequest->getQueued() > 0); + delete mCurlRequest; + mCurlRequest = NULL; + // Currently a no-op. mFinished = true; } -- cgit v1.2.3 From d2f138b4f348aac04d7940635b3ef44231291080 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 16 May 2011 18:11:55 -0500 Subject: SH-709 Fix for triangle limit value not updating when spinner is selected. --- indra/newview/llfloatermodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e8da1aa42c..44204e947b 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4044,7 +4044,7 @@ void LLModelPreview::updateStatusMessages() LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); limit->setMaxValue(mMaxTriangleLimit); - limit->setValue(mRequestedTriangleCount[mPreviewLOD]); + limit->forceSetValue(mRequestedTriangleCount[mPreviewLOD]); if (lod_mode == 0) { -- cgit v1.2.3 From a2d8f0cb3308fed1cb2c8d5fa8fb74ec4cefa45b Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 16 May 2011 19:51:16 -0500 Subject: SH-795 Cache and display LoD parameters etc for each lod. --- indra/newview/llfloatermodelpreview.cpp | 63 +++++++++++++++++----- indra/newview/llfloatermodelpreview.h | 9 +++- .../skins/default/xui/en/floater_model_preview.xml | 2 +- 3 files changed, 60 insertions(+), 14 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 44204e947b..b7e9865228 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2597,6 +2597,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mLoading = false; mLoadState = LLModelLoader::STARTING; mGroup = 0; + mLODFrozen = false; mBuildShareTolerance = 0.f; mBuildQueueMode = GLOD_QUEUE_GREEDY; mBuildBorderMode = GLOD_BORDER_UNLOCK; @@ -2605,6 +2606,13 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) for (U32 i = 0; i < LLModel::NUM_LODS; ++i) { mRequestedTriangleCount[i] = 0; + mRequestedCreaseAngle[i] = -1.f; + mRequestedLoDMode[i] = 0; + mRequestedErrorThreshold[i] = 0.f; + mRequestedBuildOperator[i] = 0; + mRequestedQueueMode[i] = 0; + mRequestedBorderMode[i] = 0; + mRequestedShareTolerance[i] = 0.f; } mViewOption["show_textures"] = false; @@ -3247,6 +3255,8 @@ void LLModelPreview::generateNormals() F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); + mRequestedCreaseAngle[which_lod] = angle_cutoff; + angle_cutoff *= DEG_TO_RAD; if (which_lod == 3 && !mBaseModel.empty()) @@ -3266,7 +3276,7 @@ void LLModelPreview::generateNormals() mVertexBuffer[which_lod].clear(); refresh(); - + updateStatusMessages(); } void LLModelPreview::clearMaterials() @@ -3342,6 +3352,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { lod_mode = iface->getFirstSelectedIndex(); } + mRequestedLoDMode[mPreviewLOD] = lod_mode; F32 lod_error_threshold = mFMP->childGetValue("lod_error_threshold").asReal(); @@ -3365,6 +3376,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { build_operator = iface->getFirstSelectedIndex(); } + mRequestedBuildOperator[mPreviewLOD] = build_operator; if (build_operator == 0) { @@ -3381,6 +3393,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { queue_mode = iface->getFirstSelectedIndex(); } + mRequestedQueueMode[mPreviewLOD] = queue_mode; if (queue_mode == 0) { @@ -3402,6 +3415,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { border_mode = iface->getFirstSelectedIndex(); } + mRequestedBorderMode[mPreviewLOD] = border_mode; if (border_mode == 0) { @@ -3437,6 +3451,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim mBuildShareTolerance = share_tolerance; object_dirty = true; } + mRequestedShareTolerance[mPreviewLOD] = share_tolerance; if (mGroup == 0) { @@ -3545,6 +3560,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim U32 submeshes = 0; mRequestedTriangleCount[lod] = triangle_count; + mRequestedErrorThreshold[lod] = lod_error_threshold; glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); stop_gloderror(); @@ -4021,6 +4037,9 @@ void LLModelPreview::updateStatusMessages() { // auto generate, also the default case for wizard which has no radio selection fmp->mLODMode[mPreviewLOD] = 1; + //don't actually regenerate lod when refreshing UI + mLODFrozen = true; + for (U32 i = 0; i < num_file_controls; ++i) { mFMP->childDisable(file_controls[i]); @@ -4033,20 +4052,21 @@ void LLModelPreview::updateStatusMessages() //if (threshold) { - U32 lod_mode = 0; - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode"); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - LLSpinCtrl* threshold = mFMP->getChild("lod_error_threshold"); LLSpinCtrl* limit = mFMP->getChild("lod_triangle_limit"); limit->setMaxValue(mMaxTriangleLimit); limit->forceSetValue(mRequestedTriangleCount[mPreviewLOD]); - if (lod_mode == 0) + threshold->forceSetValue(mRequestedErrorThreshold[mPreviewLOD]); + + mFMP->getChild("lod_mode")->selectNthItem(mRequestedLoDMode[mPreviewLOD]); + mFMP->getChild("build_operator")->selectNthItem(mRequestedBuildOperator[mPreviewLOD]); + mFMP->getChild("queue_mode")->selectNthItem(mRequestedQueueMode[mPreviewLOD]); + mFMP->getChild("border_mode")->selectNthItem(mRequestedBorderMode[mPreviewLOD]); + mFMP->getChild("share_tolerance")->setValue(mRequestedShareTolerance[mPreviewLOD]); + + if (mRequestedLoDMode[mPreviewLOD] == 0) { limit->setVisible(true); threshold->setVisible(false); @@ -4060,6 +4080,8 @@ void LLModelPreview::updateStatusMessages() threshold->setVisible(true); } } + + mLODFrozen = false; } } @@ -4075,6 +4097,20 @@ void LLModelPreview::updateStatusMessages() mFMP->childDisable("physics_file"); mFMP->childDisable("physics_browse"); } + + LLSpinCtrl* crease = mFMP->getChild("crease_angle"); + + if (mRequestedCreaseAngle[mPreviewLOD] == -1.f) + { + mFMP->childSetColor("crease_label", LLColor4::grey); + crease->forceSetValue(75.f); + } + else + { + mFMP->childSetColor("crease_label", LLColor4::white); + crease->forceSetValue(mRequestedCreaseAngle[mPreviewLOD]); + } + } void LLModelPreview::setPreviewTarget(F32 distance) @@ -4925,9 +4961,12 @@ void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture void LLModelPreview::onLODParamCommit(bool enforce_tri_limit) { - genLODs(mPreviewLOD, 3, enforce_tri_limit); - updateStatusMessages(); - refresh(); + if (!mLODFrozen) + { + genLODs(mPreviewLOD, 3, enforce_tri_limit); + updateStatusMessages(); + refresh(); + } } LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 4d8b46807f..b54a72e555 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -373,13 +373,20 @@ public: std::map mViewOption; //GLOD object parameters (must rebuild object if these change) + bool mLODFrozen; F32 mBuildShareTolerance; U32 mBuildQueueMode; U32 mBuildOperator; U32 mBuildBorderMode; + U32 mRequestedLoDMode[LLModel::NUM_LODS]; S32 mRequestedTriangleCount[LLModel::NUM_LODS]; + F32 mRequestedErrorThreshold[LLModel::NUM_LODS]; + U32 mRequestedBuildOperator[LLModel::NUM_LODS]; + U32 mRequestedQueueMode[LLModel::NUM_LODS]; + U32 mRequestedBorderMode[LLModel::NUM_LODS]; + F32 mRequestedShareTolerance[LLModel::NUM_LODS]; + F32 mRequestedCreaseAngle[LLModel::NUM_LODS]; - LLModelLoader* mModelLoader; LLModelLoader::scene mScene[LLModel::NUM_LODS]; diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index d08c3e7078..374eeeb0de 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -219,7 +219,7 @@ Generate Normals - + Crease Angle: -- cgit v1.2.3 From 0e548921730eac8d4f4791362390993f2d20b99b Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 17 May 2011 10:55:35 -0400 Subject: SH-1352 FIXED Move Material dropdown to Features tab, above Physics settings --- indra/newview/llpanelobject.cpp | 88 -------------------- indra/newview/llpanelobject.h | 5 -- indra/newview/llpanelvolume.cpp | 93 +++++++++++++++++++++- indra/newview/llpanelvolume.h | 6 +- .../newview/skins/default/xui/en/floater_tools.xml | 70 ++++++++-------- 5 files changed, 132 insertions(+), 130 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 64af6c2157..204c146f3c 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -33,11 +33,9 @@ #include "lleconomy.h" #include "llerror.h" #include "llfontgl.h" -#include "llmaterialtable.h" #include "llpermissionsflags.h" #include "llstring.h" #include "llvolume.h" -#include "material_codes.h" #include "m3math.h" // project includes @@ -57,7 +55,6 @@ #include "lltool.h" #include "lltoolcomp.h" #include "lltoolmgr.h" -#include "lltrans.h" #include "llui.h" #include "llviewerobject.h" #include "llviewerregion.h" @@ -101,17 +98,6 @@ BOOL LLPanelObject::postBuild() { setMouseOpaque(FALSE); - std::map material_name_map; - material_name_map["Stone"]= LLTrans::getString("Stone"); - material_name_map["Metal"]= LLTrans::getString("Metal"); - material_name_map["Glass"]= LLTrans::getString("Glass"); - material_name_map["Wood"]= LLTrans::getString("Wood"); - material_name_map["Flesh"]= LLTrans::getString("Flesh"); - material_name_map["Plastic"]= LLTrans::getString("Plastic"); - material_name_map["Rubber"]= LLTrans::getString("Rubber"); - material_name_map["Light"]= LLTrans::getString("Light"); - - LLMaterialTable::basic.initTableTransNames(material_name_map); //-------------------------------------------------------- // Top //-------------------------------------------------------- @@ -166,22 +152,6 @@ BOOL LLPanelObject::postBuild() //-------------------------------------------------------- - // material type popup - mComboMaterial = getChild("material"); - childSetCommitCallback("material",onCommitMaterial,this); - mComboMaterial->removeall(); - - for (LLMaterialTable::info_list_t::iterator iter = LLMaterialTable::basic.mMaterialInfoList.begin(); - iter != LLMaterialTable::basic.mMaterialInfoList.end(); ++iter) - { - LLMaterialInfo* minfop = *iter; - if (minfop->mMCode != LL_MCODE_LIGHT) - { - mComboMaterial->add(minfop->mName); - } - } - mComboMaterialItemCount = mComboMaterial->getItemCount(); - // Base Type mComboBaseType = getChild("comboBaseType"); childSetCommitCallback("comboBaseType",onCommitParametric,this); @@ -309,7 +279,6 @@ BOOL LLPanelObject::postBuild() LLPanelObject::LLPanelObject() : LLPanel(), - mComboMaterialItemCount(0), mIsPhysical(FALSE), mIsTemporary(FALSE), mIsPhantom(FALSE), @@ -527,43 +496,6 @@ void LLPanelObject::getState( ) mCheckCastShadows->setEnabled( roots_selected==1 && editable ); #endif - // Update material part - // slightly inefficient - materials are unique per object, not per TE - U8 material_code = 0; - struct f : public LLSelectedTEGetFunctor - { - U8 get(LLViewerObject* object, S32 te) - { - return object->getMaterial(); - } - } func; - bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); - std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); - if (editable && single_volume && material_same) - { - mComboMaterial->setEnabled( TRUE ); - if (material_code == LL_MCODE_LIGHT) - { - if (mComboMaterial->getItemCount() == mComboMaterialItemCount) - { - mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); - } - mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); - } - else - { - if (mComboMaterial->getItemCount() != mComboMaterialItemCount) - { - mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); - } - - mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); - } - } - else - { - mComboMaterial->setEnabled( FALSE ); - } //---------------------------------------------------------------------------- S32 selected_item = MI_BOX; @@ -1244,25 +1176,6 @@ void LLPanelObject::sendCastShadows() } } -// static -void LLPanelObject::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) -{ - //LLPanelObject* self = (LLPanelObject*) userdata; - LLComboBox* box = (LLComboBox*) ctrl; - - if (box) - { - // apply the currently selected material to the object - const std::string& material_name = box->getSimple(); - std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); - if (material_name != LEGACY_FULLBRIGHT_DESC) - { - U8 material_code = LLMaterialTable::basic.getMCode(material_name); - LLSelectMgr::getInstance()->selectionSetMaterial(material_code); - } - } -} - // static void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) { @@ -1937,7 +1850,6 @@ void LLPanelObject::clearCtrls() mCheckCastShadows->set(FALSE); mCheckCastShadows->setEnabled( FALSE ); #endif - mComboMaterial ->setEnabled( FALSE ); // Disable text labels mLabelPosition ->setEnabled( FALSE ); mLabelSize ->setEnabled( FALSE ); diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index e2f2a4400d..475dfdaedb 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -66,7 +66,6 @@ public: static void onCommitPhantom( LLUICtrl* ctrl, void* userdata); static void onCommitCastShadows( LLUICtrl* ctrl, void* userdata); static void onCommitPhysics( LLUICtrl* ctrl, void* userdata); - static void onCommitMaterial( LLUICtrl* ctrl, void* userdata); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -94,10 +93,6 @@ protected: void getVolumeParams(LLVolumeParams& volume_params); protected: - S32 mComboMaterialItemCount; - - LLComboBox* mComboMaterial; - // Per-object options LLComboBox* mComboBaseType; diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index c443814c89..0803fea004 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -59,6 +59,7 @@ #include "lltool.h" #include "lltoolcomp.h" #include "lltoolmgr.h" +#include "lltrans.h" #include "llui.h" #include "llviewerobject.h" #include "llviewerregion.h" @@ -156,6 +157,34 @@ BOOL LLPanelVolume::postBuild() mSpinPhysicsRestitution = getChild("Physics Restitution"); mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution)); } + + std::map material_name_map; + material_name_map["Stone"]= LLTrans::getString("Stone"); + material_name_map["Metal"]= LLTrans::getString("Metal"); + material_name_map["Glass"]= LLTrans::getString("Glass"); + material_name_map["Wood"]= LLTrans::getString("Wood"); + material_name_map["Flesh"]= LLTrans::getString("Flesh"); + material_name_map["Plastic"]= LLTrans::getString("Plastic"); + material_name_map["Rubber"]= LLTrans::getString("Rubber"); + material_name_map["Light"]= LLTrans::getString("Light"); + + LLMaterialTable::basic.initTableTransNames(material_name_map); + + // material type popup + mComboMaterial = getChild("material"); + childSetCommitCallback("material",onCommitMaterial,this); + mComboMaterial->removeall(); + + for (LLMaterialTable::info_list_t::iterator iter = LLMaterialTable::basic.mMaterialInfoList.begin(); + iter != LLMaterialTable::basic.mMaterialInfoList.end(); ++iter) + { + LLMaterialInfo* minfop = *iter; + if (minfop->mMCode != LL_MCODE_LIGHT) + { + mComboMaterial->add(minfop->mName); + } + } + mComboMaterialItemCount = mComboMaterial->getItemCount(); // Start with everyone disabled clearCtrls(); @@ -164,7 +193,8 @@ BOOL LLPanelVolume::postBuild() } LLPanelVolume::LLPanelVolume() - : LLPanel() + : LLPanel(), + mComboMaterialItemCount(0) { setMouseOpaque(FALSE); @@ -379,6 +409,46 @@ void LLPanelVolume::getState( ) getChildView("FlexForceZ")->setEnabled(false); } + // Material properties + + // Update material part + // slightly inefficient - materials are unique per object, not per TE + U8 material_code = 0; + struct f : public LLSelectedTEGetFunctor + { + U8 get(LLViewerObject* object, S32 te) + { + return object->getMaterial(); + } + } func; + bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); + std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); + if (editable && single_volume && material_same) + { + mComboMaterial->setEnabled( TRUE ); + if (material_code == LL_MCODE_LIGHT) + { + if (mComboMaterial->getItemCount() == mComboMaterialItemCount) + { + mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); + } + mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); + } + else + { + if (mComboMaterial->getItemCount() != mComboMaterialItemCount) + { + mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); + } + + mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); + } + } + else + { + mComboMaterial->setEnabled( FALSE ); + } + // Physics properties mSpinPhysicsGravity->set(objectp->getPhysicsGravity()); @@ -522,6 +592,8 @@ void LLPanelVolume::clearCtrls() mSpinPhysicsFriction->setEnabled(FALSE); mSpinPhysicsDensity->setEnabled(FALSE); mSpinPhysicsRestitution->setEnabled(FALSE); + + mComboMaterial->setEnabled( FALSE ); } // @@ -673,6 +745,25 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) } } +// static +void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) +{ + //LLPanelObject* self = (LLPanelObject*) userdata; + LLComboBox* box = (LLComboBox*) ctrl; + + if (box) + { + // apply the currently selected material to the object + const std::string& material_name = box->getSimple(); + std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); + if (material_name != LEGACY_FULLBRIGHT_DESC) + { + U8 material_code = LLMaterialTable::basic.getMCode(material_name); + LLSelectMgr::getInstance()->selectionSetMaterial(material_code); + } + } +} + // static void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) { diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 776a2c1f4a..0ef47db0d9 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -63,8 +63,8 @@ public: static void onCommitLight( LLUICtrl* ctrl, void* userdata); static void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata); static void onCommitFlexible( LLUICtrl* ctrl, void* userdata); - static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata); + static void onCommitMaterial( LLUICtrl* ctrl, void* userdata); void onLightCancelColor(const LLSD& data); void onLightSelectColor(const LLSD& data); @@ -104,6 +104,10 @@ protected: LLSpinCtrl* mSpinForce[3]; */ + S32 mComboMaterialItemCount; + LLComboBox* mComboMaterial; + + LLColor4 mLightSavedColor; LLUUID mLightSavedTexture; LLPointer mObject; diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 05d47506db..edc829cb9c 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1608,41 +1608,6 @@ even though the user gets a free copy. name="Sculpted" value="Sculpted" /> - - - - - - - - - + + + + + + + + + Date: Tue, 17 May 2011 10:56:40 -0400 Subject: SH-1343 FIXED Change wizard slider labels --- indra/newview/skins/default/xui/en/floater_model_wizard.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml index 92d57b20be..47b2e5fd79 100644 --- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml +++ b/indra/newview/skins/default/xui/en/floater_model_wizard.xml @@ -572,9 +572,9 @@ Advanced users familiar with 3d content creation tools may prefer to use the [se bg_opaque_color="DkGray2" background_visible="true" background_opaque="true"> - Performance + Higher Performance Faster rendering but less detailed; lowers Resource (prim) cost. - Accuracy + Higher Accuracy More detailed model but slower; increases Resource (prim) cost. Date: Tue, 17 May 2011 10:57:19 -0400 Subject: SH-1351 FIXED On the Edit Panel, remove the Override Material checkbox --- indra/newview/llpanelvolume.cpp | 1 - indra/newview/skins/default/xui/en/floater_tools.xml | 10 ---------- 2 files changed, 11 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 0803fea004..ebddaa90bc 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -537,7 +537,6 @@ void LLPanelVolume::refresh() getChildView("label physicsshapetype")->setVisible(enable_mesh); getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh); getChildView("Physics Gravity")->setVisible(enable_mesh); - getChildView("Physics Material Override")->setVisible(enable_mesh); getChildView("Physics Friction")->setVisible(enable_mesh); getChildView("Physics Density")->setVisible(enable_mesh); getChildView("Physics Restitution")->setVisible(enable_mesh); diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index edc829cb9c..40bf7bfed7 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2441,16 +2441,6 @@ even though the user gets a free copy. top_pad="10" width="132" /> - - Date: Tue, 17 May 2011 10:57:56 -0400 Subject: SH-1419 FIXED Sim complains about changing physical materials when Physics, Temporary, or Phantom is changed. --- indra/newview/llselectmgr.cpp | 10 +++++----- indra/newview/llviewerobject.cpp | 17 ++++++++++------- indra/newview/llviewerobject.h | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) (limited to 'indra') diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 9b264b81c7..8fa4065fa6 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1997,7 +1997,7 @@ void LLSelectMgr::selectionSetPhysicsType(U8 type) if (object->permModify()) { object->setPhysicsShapeType(mType); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2016,7 +2016,7 @@ void LLSelectMgr::selectionSetFriction(F32 friction) if (object->permModify()) { object->setPhysicsFriction(mFriction); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2035,7 +2035,7 @@ void LLSelectMgr::selectionSetGravity(F32 gravity ) if (object->permModify()) { object->setPhysicsGravity(mGravity); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2054,7 +2054,7 @@ void LLSelectMgr::selectionSetDensity(F32 density ) if (object->permModify()) { object->setPhysicsDensity(mDensity); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } @@ -2073,7 +2073,7 @@ void LLSelectMgr::selectionSetRestitution(F32 restitution) if (object->permModify()) { object->setPhysicsRestitution(mRestitution); - object->updateFlags(); + object->updateFlags(TRUE); } return true; } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 6d493bfcd5..f5fee662e6 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5282,7 +5282,7 @@ bool LLViewerObject::specialHoverCursor() const || (mClickAction != 0); } -void LLViewerObject::updateFlags() +void LLViewerObject::updateFlags(BOOL physics_changed) { LLViewerRegion* regionp = getRegion(); if(!regionp) return; @@ -5295,12 +5295,15 @@ void LLViewerObject::updateFlags() gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); - gMessageSystem->nextBlock("ExtraPhysics"); - gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() ); - gMessageSystem->addF32("Density", getPhysicsDensity() ); - gMessageSystem->addF32("Friction", getPhysicsFriction() ); - gMessageSystem->addF32("Restitution", getPhysicsRestitution() ); - gMessageSystem->addF32("GravityMultiplier", getPhysicsGravity() ); + 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() ); } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index e417343bec..21198f7dd1 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -488,7 +488,7 @@ public: void setRegion(LLViewerRegion *regionp); virtual void updateRegion(LLViewerRegion *regionp); - void updateFlags(); + void updateFlags(BOOL physics_changed = FALSE); BOOL setFlags(U32 flag, BOOL state); void setPhysicsShapeType(U8 type); void setPhysicsGravity(F32 gravity); -- cgit v1.2.3 From 7e977d05f20a15e2ee17522a19624f061722580e Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Tue, 17 May 2011 10:58:21 -0400 Subject: SH-1444 FIXED "Allow mesh objects" setting is visible on a non-mesh region. --- indra/newview/llfloaterregioninfo.cpp | 5 +++++ indra/newview/skins/default/xui/en/panel_region_general.xml | 1 + 2 files changed, 6 insertions(+) (limited to 'indra') diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 34fda49375..fc6976755f 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -590,6 +590,11 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) getChildView("im_btn")->setEnabled(allow_modify); getChildView("manage_telehub_btn")->setEnabled(allow_modify); + const bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && + gAgent.getRegion() && + !gAgent.getRegion()->getCapability("GetMesh").empty(); + getChildView("mesh_rez_enabled_check")->setVisible(enable_mesh); + getChildView("mesh_rez_enabled_check")->setEnabled(getChildView("mesh_rez_enabled_check")->getEnabled() && enable_mesh); // Data gets filled in by processRegionInfo return LLPanelRegionInfo::refreshFromRegion(region); diff --git a/indra/newview/skins/default/xui/en/panel_region_general.xml b/indra/newview/skins/default/xui/en/panel_region_general.xml index e0d9f3f714..3f9195d092 100644 --- a/indra/newview/skins/default/xui/en/panel_region_general.xml +++ b/indra/newview/skins/default/xui/en/panel_region_general.xml @@ -134,6 +134,7 @@ top="190" width="80" /> Date: Tue, 17 May 2011 10:58:42 -0400 Subject: SH-1506 FIXED "Upload Wizard" is missing from Inventory's add menu --- indra/newview/skins/default/xui/en/menu_inventory_add.xml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index 484af63097..b36b82ebd8 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -42,7 +42,7 @@ - @@ -54,6 +54,18 @@ + + + + + Date: Tue, 17 May 2011 11:02:28 -0400 Subject: SH-769 FIXED Name field in upload model dialog allows 255 characters... --- indra/newview/skins/default/xui/en/floater_model_preview.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 374eeeb0de..85535c2078 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -23,7 +23,7 @@ Simplifying... - + Name: Date: Tue, 17 May 2011 18:18:10 -0400 Subject: SH-1580 FIXED Disable mesh mirroring in build tools & on server --- indra/newview/llpanelobject.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 204c146f3c..34a92cd0ac 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1027,12 +1027,9 @@ void LLPanelObject::getState( ) mCtrlSculptTexture->setVisible(sculpt_texture_visible); mLabelSculptType->setVisible(sculpt_texture_visible); mCtrlSculptType->setVisible(sculpt_texture_visible); - mCtrlSculptMirror->setVisible(sculpt_texture_visible); - mCtrlSculptInvert->setVisible(sculpt_texture_visible); // sculpt texture - if (selected_item == MI_SCULPT) { @@ -1077,7 +1074,7 @@ void LLPanelObject::getState( ) if (mCtrlSculptMirror) { mCtrlSculptMirror->set(sculpt_mirror); - mCtrlSculptMirror->setEnabled(editable); + mCtrlSculptMirror->setEnabled(editable && !isMesh); } if (mCtrlSculptInvert) @@ -1098,6 +1095,9 @@ void LLPanelObject::getState( ) mSculptTextureRevert = LLUUID::null; } + mCtrlSculptMirror->setVisible(sculpt_texture_visible && !isMesh); + mCtrlSculptInvert->setVisible(sculpt_texture_visible && !isMesh); + //---------------------------------------------------------------------------- mObject = objectp; -- cgit v1.2.3 From f9ac182865ac31eb03668a628e100d94c35eab53 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 17 May 2011 23:47:29 -0500 Subject: SH-1555 Disable upload button if a hull exists that has more than 256 vertices. --- indra/newview/llfloatermodelpreview.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'indra') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b7e9865228..241e908d8c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3848,6 +3848,18 @@ void LLModelPreview::updateStatusMessages() } } + + //make sure no hulls have more than 256 points in them + for (U32 i = 0; upload_ok && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i]; + + for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j) + { + upload_ok = upload_ok && mdl->mPhysics.mHull[i].size() <= 256; + } + } + bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false; bool skinAndRigOk = true; @@ -3871,6 +3883,10 @@ void LLModelPreview::updateStatusMessages() { mFMP->childEnable("ok_btn"); } + else + { + mFMP->childDisable("ok_btn"); + } //add up physics triangles etc S32 start = 0; -- cgit v1.2.3 From e237f5733ca453fa51a16f9f88da265be201a607 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 18 May 2011 01:30:21 -0500 Subject: SH-914 Fix for normals getting screwed up by non-uniform model normalization. --- indra/llprimitive/llmodel.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'indra') diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 794cdb83d5..57ac7a143f 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -991,6 +991,9 @@ void LLModel::normalizeVolumeFaces() scale.splat(1.f); scale.div(size); + LLVector4a inv_scale(1.f); + inv_scale.div(scale); + for (U32 i = 0; i < mVolumeFaces.size(); ++i) { LLVolumeFace& face = mVolumeFaces[i]; @@ -1007,10 +1010,14 @@ void LLModel::normalizeVolumeFaces() // For all the positions, we scale // the positions to fit within the unit cube. LLVector4a* pos = (LLVector4a*) face.mPositions; + LLVector4a* norm = (LLVector4a*) face.mNormals; + for (U32 j = 0; j < face.mNumVertices; ++j) { pos[j].add(trans); pos[j].mul(scale); + norm[j].mul(inv_scale); + norm[j].normalize3(); } } -- cgit v1.2.3 From 4374f53e23c9d999206764b0b38473337720c1c3 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 18 May 2011 02:02:52 -0500 Subject: SH-1586 Fix for bad camera behavior introduced by SH-1119 --- indra/newview/llagentcamera.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index c6b5a0113f..80085dad9d 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -394,7 +394,9 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi LLQuaternion inv_obj_rot = ~obj_rot; // get inverse of rotation LLVector3 object_extents; const LLVector4a* oe4 = object->mDrawable->getSpatialExtents(); - object_extents.set( oe4[1][0], oe4[1][1], oe4[1][2] ); + LLVector4a size; + size.setSub(oe4[1], oe4[0]); + object_extents.set( size[0], size[1], size[2] ); // make sure they object extents are non-zero object_extents.clamp(0.001f, F32_MAX); -- cgit v1.2.3 From 7a02501aae8a21f4bf552d47e0799c4abdcd4228 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 18 May 2011 09:47:58 -0400 Subject: SH-1492 WIP --- indra/newview/llmeshrepository.cpp | 32 ++++++++++++++++++++++++++++++-- indra/newview/llmeshrepository.h | 3 ++- 2 files changed, 32 insertions(+), 3 deletions(-) mode change 100644 => 100755 indra/newview/llmeshrepository.cpp mode change 100644 => 100755 indra/newview/llmeshrepository.h (limited to 'indra') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp old mode 100644 new mode 100755 index 922291c9e1..5305f3dbca --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -499,6 +499,27 @@ public: llinfos << "completed" << llendl; mThread->mPendingUploads--; dumpLLSDToFile(content,"whole_model_response.xml"); + + mThread->mWholeModelUploadURL = content["uploader"]; + } +}; + +class LLWholeModelUploadResponder: public LLCurl::Responder +{ + LLMeshUploadThread* mThread; +public: + LLWholeModelUploadResponder(LLMeshUploadThread* thread): + mThread(thread) + { + } + virtual void completed(U32 status, + const std::string& reason, + const LLSD& content) + { + //assert_main_thread(); + llinfos << "upload completed" << llendl; + mThread->mPendingUploads--; + dumpLLSDToFile(content,"whole_model_upload_response.xml"); } }; @@ -1263,7 +1284,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadObjectAssetCapability = gAgent.getRegion()->getCapability("UploadObjectAsset"); mNewInventoryCapability = gAgent.getRegion()->getCapability("NewFileAgentInventoryVariablePrice"); - mWholeModelUploadCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory"); + mWholeModelFeeCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory"); mOrigin += gAgent.getAtAxis() * scale.magVec(); } @@ -1548,7 +1569,7 @@ void LLMeshUploadThread::doWholeModelUpload() mPendingUploads++; LLCurlRequest::headers_t headers; - mCurlRequest->post(mWholeModelUploadCapability, headers, model_data, + mCurlRequest->post(mWholeModelFeeCapability, headers, model_data, new LLWholeModelFeeResponder(this)); do @@ -1556,6 +1577,13 @@ void LLMeshUploadThread::doWholeModelUpload() mCurlRequest->process(); } while (mCurlRequest->getQueued() > 0); + mCurlRequest->post(mWholeModelUploadURL, headers, model_data["asset_resources"], new LLWholeModelUploadResponder(this)); + + do + { + mCurlRequest->process(); + } while (mCurlRequest->getQueued() > 0); + delete mCurlRequest; mCurlRequest = NULL; diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h old mode 100644 new mode 100755 index 802e3e1aba..f859e29c07 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -387,7 +387,8 @@ public: LLHost mHost; std::string mUploadObjectAssetCapability; std::string mNewInventoryCapability; - std::string mWholeModelUploadCapability; + std::string mWholeModelFeeCapability; + std::string mWholeModelUploadURL; std::queue mUploadQ; std::queue mConfirmedQ; -- cgit v1.2.3 From 3990324e8f8391aee335ad74b33b22e0b1c849af Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 18 May 2011 11:33:28 -0400 Subject: trying to fix mac build complaints --- indra/newview/llmeshrepository.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 5305f3dbca..d9a58d56fe 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -500,7 +500,7 @@ public: mThread->mPendingUploads--; dumpLLSDToFile(content,"whole_model_response.xml"); - mThread->mWholeModelUploadURL = content["uploader"]; + mThread->mWholeModelUploadURL = content["uploader"].asString(); } }; @@ -1389,7 +1389,7 @@ void LLMeshUploadThread::run() #if 1 void dumpLLSDToFile(const LLSD& content, std::string filename) { - std::ofstream of(filename); + std::ofstream of(filename.c_str()); LLSDSerialize::toPrettyXML(content,of); } #endif -- cgit v1.2.3 From c84e84cfbf101deb0a920bd95b3a8a7b16806d04 Mon Sep 17 00:00:00 2001 From: prep Date: Wed, 18 May 2011 15:56:24 -0400 Subject: Fix for sh-1227. Decoupled avatar in preview window from in world avatar. Code cleanup. --- indra/newview/llfloatermodelpreview.cpp | 103 +++++++++++--------------------- indra/newview/llfloatermodelpreview.h | 4 ++ 2 files changed, 38 insertions(+), 69 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 241e908d8c..9dd5269a6b 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -98,7 +98,8 @@ #include "llvfile.h" #include "llvfs.h" #include "llcallbacklist.h" - +#include "llviewerobjectlist.h" +#include "llanimationstates.h" #include "glod/glod.h" //static @@ -381,12 +382,6 @@ LLFloaterModelPreview::~LLFloaterModelPreview() { sInstance = NULL; - if ( mModelPreview && mModelPreview->getResetJointFlag() ) - { - gAgentAvatarp->resetJointPositions(); - } - - if ( mModelPreview ) { delete mModelPreview; @@ -1577,7 +1572,7 @@ bool LLModelLoader::doLoadModel() { //llinfos<<"joint "<getJoint( lookingForJoint ); + LLJoint* pJoint = mPreview->getPreviewAvatar()->getJoint( lookingForJoint ); if ( pJoint ) { pJoint->storeCurrentXform( jointTransform.getTranslation() ); @@ -2657,6 +2652,8 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mMasterLegacyJointList.push_front("mHipLeft"); mMasterLegacyJointList.push_front("mKneeLeft"); mMasterLegacyJointList.push_front("mFootLeft"); + + createPreviewAvatar(); } LLModelPreview::~LLModelPreview() @@ -2710,7 +2707,7 @@ U32 LLModelPreview::calcResourceCost() if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() ) { - gAgentAvatarp->setPelvisOffset( mPelvisZOffset ); + getPreviewAvatar()->setPelvisOffset( mPelvisZOffset ); } F32 streaming_cost = 0.f; @@ -4293,42 +4290,6 @@ void LLModelPreview::update() } //----------------------------------------------------------------------------- -// changeAvatarsJointPositions() -//----------------------------------------------------------------------------- -void LLModelPreview::changeAvatarsJointPositions( LLModel* pModel ) -{ - if ( mMasterJointList.empty() ) - { - return; - } - - std::vector :: const_iterator jointListItBegin = pModel->mSkinInfo.mJointNames.begin(); - std::vector :: const_iterator jointListItEnd = pModel->mSkinInfo.mJointNames.end(); - - S32 index = 0; - for ( ; jointListItBegin!=jointListItEnd; ++jointListItBegin, ++index ) - { - std::string elem = *jointListItBegin; - //llinfos<<"joint "<mSkinInfo.mAlternateBindMatrix.size(); - if ( matrixCnt < 1 ) - { - llinfos<<"Total WTF moment :"<mSkinInfo.mAlternateBindMatrix[index]; - - LLJoint* pJoint = gAgentAvatarp->getJoint( elem ); - if ( pJoint ) - { - pJoint->storeCurrentXform( jointTransform.getTranslation() ); - } - } - } -} -//----------------------------------------------------------------------------- // getTranslationForJointOffset() //----------------------------------------------------------------------------- LLVector3 LLModelPreview::getTranslationForJointOffset( std::string joint ) @@ -4341,6 +4302,30 @@ LLVector3 LLModelPreview::getTranslationForJointOffset( std::string joint ) } return LLVector3(0.0f,0.0f,0.0f); } +//----------------------------------------------------------------------------- +// createPreviewAvatar +//----------------------------------------------------------------------------- +void LLModelPreview::createPreviewAvatar( void ) +{ + mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion() ); + if ( mPreviewAvatar ) + { + mPreviewAvatar->createDrawable( &gPipeline ); + mPreviewAvatar->mIsDummy = TRUE; + mPreviewAvatar->mSpecialRenderMode = 1; + mPreviewAvatar->setPositionAgent( LLVector3::zero ); + mPreviewAvatar->slamPosition(); + mPreviewAvatar->updateJointLODs(); + mPreviewAvatar->updateGeometry( mPreviewAvatar->mDrawable ); + mPreviewAvatar->startMotion( ANIM_AGENT_STAND ); + mPreviewAvatar->hideSkirt(); + } + else + { + llinfos<<"Failed to create preview avatar for upload model window"<childSetEnabled("upload_joints", upload_skin); - //poke at avatar when we upload custom joints - /* - if ( upload_joints ) - { - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) - { - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { - LLModelInstance& instance = *model_iter; - LLModel* model = instance.mModel; - if ( !model->mSkinWeights.empty() ) - { - changeAvatarsJointPositions( model ); - } - } - } - } - */ - F32 explode = mFMP->childGetValue("physics_explode").asReal(); glClear(GL_DEPTH_BUFFER_BIT); @@ -4493,7 +4459,7 @@ BOOL LLModelPreview::render() if (skin_weight) { - target_pos = gAgentAvatarp->getPositionAgent(); + target_pos = getPreviewAvatar()->getPositionAgent(); z_near = 0.01f; z_far = 1024.f; mCameraDistance = 16.f; @@ -4713,8 +4679,7 @@ BOOL LLModelPreview::render() } else { - LLVOAvatarSelf* avatar = gAgentAvatarp; - target_pos = avatar->getPositionAgent(); + target_pos = getPreviewAvatar()->getPositionAgent(); LLViewerCamera::getInstance()->setOriginAndLookAt( target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera @@ -4723,7 +4688,7 @@ BOOL LLModelPreview::render() if (joint_positions) { - avatar->renderCollisionVolumes(); + getPreviewAvatar()->renderCollisionVolumes(); } for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) @@ -4754,7 +4719,7 @@ BOOL LLModelPreview::render() LLMatrix4 mat[64]; for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j) { - LLJoint* joint = avatar->getJoint(model->mSkinInfo.mJointNames[j]); + LLJoint* joint = getPreviewAvatar()->getJoint(model->mSkinInfo.mJointNames[j]); if (joint) { mat[j] = model->mSkinInfo.mInvBindMatrix[j]; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index b54a72e555..f6d4a08d1f 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -341,6 +341,9 @@ public: LLVector3 getTranslationForJointOffset( std::string joint ); + void createPreviewAvatar( void ); + LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; } + protected: friend class LLModelLoader; friend class LLFloaterModelPreview; @@ -422,6 +425,7 @@ public: std::deque mMasterLegacyJointList; std::deque mJointsFromNode; JointTransformMap mJointTransformMap; + LLPointer mPreviewAvatar; }; #endif // LL_LLFLOATERMODELPREVIEW_H -- cgit v1.2.3 From bd5801ef62882bbe58edf0a0fb6c0f5bf950efa1 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 19 May 2011 13:53:47 -0400 Subject: SH-769 FIXED Name field in model dialog allows 255 characters --- indra/newview/skins/default/xui/en/floater_model_preview.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 85535c2078..dce55dae12 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -23,10 +23,10 @@ Simplifying... - + Name: - -- cgit v1.2.3 From 19a06478d9863c451450b7c9e2f931ba587a3cec Mon Sep 17 00:00:00 2001 From: Leslie Linden Date: Thu, 19 May 2011 17:28:23 -0700 Subject: SH-1618 FIX -- Lighting and shadows crash ATI macs * Fixed ATI mac "lighting and shadows" related crash * Fixed up numerous GL errors on macs related to multiple color formats, the use of glEnable/glDisable on textures above the texture unit count and old ATI-specific code that was not appropriate for Mac. * Disabled SSAO for ATI macs due to it not working with shadows * Ongoing work to properly get shadows and SSAO functioning on ATI macs is required. Reviewed by davep --- indra/llrender/llgl.cpp | 10 ++++ indra/llrender/llgl.h | 1 + indra/llrender/llrender.cpp | 32 ++++++++++-- indra/llrender/llrendertarget.cpp | 1 + .../shaders/class1/deferred/multiPointLightF.glsl | 61 ++++++++++++---------- indra/newview/featuretable_mac.txt | 3 ++ indra/newview/llfeaturemanager.cpp | 2 +- indra/newview/pipeline.cpp | 17 +++++- 8 files changed, 94 insertions(+), 33 deletions(-) (limited to 'indra') diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index f29ee0e57e..a460912e70 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -328,6 +328,7 @@ LLGLManager::LLGLManager() : mHasShaderObjects(FALSE), mHasVertexShader(FALSE), mHasFragmentShader(FALSE), + mNumTextureImageUnits(0), mHasOcclusionQuery(FALSE), mHasOcclusionQuery2(FALSE), mHasPointParameters(FALSE), @@ -534,6 +535,13 @@ bool LLGLManager::initGL() return false; } + if (mHasFragmentShader) + { + GLint num_tex_image_units; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units); + mNumTextureImageUnits = num_tex_image_units; + } + setToDebugGPU(); initGLStates(); @@ -878,11 +886,13 @@ void LLGLManager::initExtensions() LL_INFOS("RenderInit") << "Disabling mip-map generation for Intel GPUs" << LL_ENDL; mHasMipMapGeneration = FALSE; } +#if !LL_DARWIN if (mIsATI && mHasMipMapGeneration) { LL_INFOS("RenderInit") << "Disabling mip-map generation for ATI GPUs (performance opt)" << LL_ENDL; mHasMipMapGeneration = FALSE; } +#endif // Misc glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 3d002fd8c4..1d7ab188fc 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -91,6 +91,7 @@ public: BOOL mHasShaderObjects; BOOL mHasVertexShader; BOOL mHasFragmentShader; + S32 mNumTextureImageUnits; BOOL mHasOcclusionQuery; BOOL mHasOcclusionQuery2; BOOL mHasPointParameters; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 49e10c4790..c37139ac4c 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -119,14 +119,29 @@ void LLTexUnit::refreshState(void) gGL.flush(); glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); + + // + // Per apple spec, don't call glEnable/glDisable when index exceeds max texture units + // http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html + // + bool enableDisable = (mIndex < gGLManager.mNumTextureUnits); + if (mCurrTexType != TT_NONE) { - glEnable(sGLTextureType[mCurrTexType]); + if (enableDisable) + { + glEnable(sGLTextureType[mCurrTexType]); + } + glBindTexture(sGLTextureType[mCurrTexType], mCurrTexture); } else { - glDisable(GL_TEXTURE_2D); + if (enableDisable) + { + glDisable(GL_TEXTURE_2D); + } + glBindTexture(GL_TEXTURE_2D, 0); } @@ -167,7 +182,11 @@ void LLTexUnit::enable(eTextureType type) mCurrTexType = type; gGL.flush(); - glEnable(sGLTextureType[type]); + + if (mIndex < gGLManager.mNumTextureUnits) + { + glEnable(sGLTextureType[type]); + } } } @@ -180,7 +199,12 @@ void LLTexUnit::disable(void) activate(); unbind(mCurrTexType); gGL.flush(); - glDisable(sGLTextureType[mCurrTexType]); + + if (mIndex < gGLManager.mNumTextureUnits) + { + glDisable(sGLTextureType[mCurrTexType]); + } + mCurrTexType = TT_NONE; } } diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index cd2556d435..da1e94df64 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -44,6 +44,7 @@ void check_framebuffer_status() case GL_FRAMEBUFFER_COMPLETE: break; default: + llwarns << "check_framebuffer_status failed -- " << std::hex << status << llendl; ll_fail("check_framebuffer_status failed"); break; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl index c5ddf31ac0..609fc4f14f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl @@ -23,8 +23,9 @@ uniform float sun_wash; uniform int light_count; -uniform vec4 light[16]; -uniform vec4 light_col[16]; +#define MAX_LIGHT_COUNT 16 +uniform vec4 light[MAX_LIGHT_COUNT]; +uniform vec4 light_col[MAX_LIGHT_COUNT]; varying vec4 vary_fragcoord; uniform vec2 screen_res; @@ -63,50 +64,56 @@ void main() float noise = texture2D(noiseMap, frag.xy/128.0).b; vec3 out_col = vec3(0,0,0); vec3 npos = normalize(-pos); - - for (int i = 0; i < light_count; ++i) + + // As of OSX 10.6.7 ATI Apple's crash when using a variable size loop + for (int i = 0; i < MAX_LIGHT_COUNT; ++i) { + bool light_contrib = (i < light_count); + vec3 lv = light[i].xyz-pos; float dist2 = dot(lv,lv); dist2 /= light[i].w; if (dist2 > 1.0) { - continue; + light_contrib = false; } float da = dot(norm, lv); if (da < 0.0) { - continue; + light_contrib = false; } - - lv = normalize(lv); - da = dot(norm, lv); - - float fa = light_col[i].a+1.0; - float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - dist_atten *= noise; - - float lit = da * dist_atten; - vec3 col = light_col[i].rgb*lit*diff; - //vec3 col = vec3(dist2, light_col[i].a, lit); - - if (spec.a > 0.0) + if (light_contrib) { - //vec3 ref = dot(pos+lv, norm); + lv = normalize(lv); + da = dot(norm, lv); + + float fa = light_col[i].a+1.0; + float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + dist_atten *= noise; + + float lit = da * dist_atten; - float sa = dot(normalize(lv+npos),norm); + vec3 col = light_col[i].rgb*lit*diff; + //vec3 col = vec3(dist2, light_col[i].a, lit); - if (sa > 0.0) + if (spec.a > 0.0) { - sa = texture2D(lightFunc,vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0); - sa *= noise; - col += da*sa*light_col[i].rgb*spec.rgb; + //vec3 ref = dot(pos+lv, norm); + + float sa = dot(normalize(lv+npos),norm); + + if (sa > 0.0) + { + sa = texture2D(lightFunc,vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0); + sa *= noise; + col += da*sa*light_col[i].rgb*spec.rgb; + } } + + out_col += col; } - - out_col += col; } if (dot(out_col, out_col) <= 0.0) diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index c075c660f3..e2b979d9e9 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -281,6 +281,9 @@ RenderVBOEnable 1 0 list TexUnit8orLess RenderDeferredSSAO 0 0 +list ATI +RenderDeferredSSAO 0 0 + list Intel RenderAnisotropic 1 0 RenderLocalLights 1 0 diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 524d2d74ef..b7aabe2aeb 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -753,7 +753,7 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("OpenGLPre30"); } - if (gGLManager.mNumTextureUnits <= 8) + if (gGLManager.mNumTextureImageUnits <= 8) { maskFeatures("TexUnit8orLess"); } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index f64eb89866..845a87b8cf 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -625,8 +625,14 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); addDeferredAttachments(mDeferredScreen); - mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + +#if LL_DARWIN + // As of OS X 10.6.7, Apple doesn't support multiple color formats in a single FBO + mEdgeMap.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); +#else mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); +#endif if (shadow_detail > 0 || ssao) { //only need mDeferredLight[0] for shadows OR ssao @@ -651,7 +657,12 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) mDeferredLight[2].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); for (U32 i = 0; i < 2; i++) { +#if LL_DARWIN + // As of OS X 10.6.7, Apple doesn't support multiple color formats in a single FBO + mGIMapPost[i].allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); +#else mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE); +#endif } } else @@ -666,8 +677,12 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale"); +#if LL_DARWIN + U32 shadow_fmt = 0; +#else //HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug) U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0; +#endif if (shadow_detail > 0) { //allocate 4 sun shadow maps -- cgit v1.2.3 From 0b612741d53a044a0179e1c32018bf8cd4213631 Mon Sep 17 00:00:00 2001 From: prep linden Date: Fri, 20 May 2011 14:26:05 -0400 Subject: SH-1252 and SH-1253 WIP. --- indra/llcommon/CMakeLists.txt | 1 + indra/llcommon/llaccountingquota.h | 78 +++++++++ indra/llinventory/llparcel.cpp | 9 + indra/llinventory/llparcel.h | 13 +- indra/newview/CMakeLists.txt | 2 + indra/newview/llaccountingquotamanager.cpp | 264 +++++++++++++++++++++++++++++ indra/newview/llaccountingquotamanager.h | 60 +++++++ indra/newview/llfloatertools.cpp | 1 + indra/newview/llviewerobject.cpp | 8 + indra/newview/llviewerobject.h | 9 +- indra/newview/llviewerobjectlist.cpp | 9 + indra/newview/llviewerobjectlist.h | 3 + indra/newview/llviewerregion.cpp | 6 + indra/newview/llviewerregion.h | 1 + 14 files changed, 459 insertions(+), 5 deletions(-) create mode 100644 indra/llcommon/llaccountingquota.h create mode 100644 indra/newview/llaccountingquotamanager.cpp create mode 100644 indra/newview/llaccountingquotamanager.h (limited to 'indra') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 80df91a5c1..9910281b64 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -115,6 +115,7 @@ set(llcommon_HEADER_FILES indra_constants.h linden_common.h linked_lists.h + llaccountingquota.h llallocator.h llallocator_heap_profile.h llagentconstants.h diff --git a/indra/llcommon/llaccountingquota.h b/indra/llcommon/llaccountingquota.h new file mode 100644 index 0000000000..f52d94f868 --- /dev/null +++ b/indra/llcommon/llaccountingquota.h @@ -0,0 +1,78 @@ +/** + * @file llaccountingquota.h + * @ + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, 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$ + */ + +#ifndef LL_ACCOUNTINGQUOTA_H +#define LL_ACCOUNTINGQUOTA_H + +struct ParcelQuota +{ + ParcelQuota( F32 ownerRenderCost, F32 ownerPhysicsCost, F32 ownerNetworkCost, F32 ownerSimulationCost, + F32 groupRenderCost, F32 groupPhysicsCost, F32 groupNetworkCost, F32 groupSimulationCost, + F32 otherRenderCost, F32 otherPhysicsCost, F32 otherNetworkCost, F32 otherSimulationCost, + F32 totalRenderCost, F32 totalPhysicsCost, F32 totalNetworkCost, F32 totalSimulationCost) + : mOwnerRenderCost( ownerRenderCost ), mOwnerPhysicsCost( ownerPhysicsCost ) + , mOwnerNetworkCost( ownerNetworkCost ), mOwnerSimulationCost( ownerSimulationCost ) + , mGroupRenderCost( groupRenderCost ), mGroupPhysicsCost( groupPhysicsCost ) + , mGroupNetworkCost( groupNetworkCost ), mGroupSimulationCost( groupSimulationCost ) + , mOtherRenderCost( otherRenderCost ), mOtherPhysicsCost( otherPhysicsCost ) + , mOtherNetworkCost( otherNetworkCost ), mOtherSimulationCost( otherSimulationCost ) + , mTotalRenderCost( totalRenderCost ), mTotalPhysicsCost( totalPhysicsCost ) + , mTotalNetworkCost( totalNetworkCost ), mTotalSimulationCost( totalSimulationCost ) + { + } + ParcelQuota(){} + F32 mOwnerRenderCost, mOwnerPhysicsCost, mOwnerNetworkCost, mOwnerSimulationCost; + F32 mGroupRenderCost, mGroupPhysicsCost, mGroupNetworkCost, mGroupSimulationCost; + F32 mOtherRenderCost, mOtherPhysicsCost, mOtherNetworkCost, mOtherSimulationCost; + F32 mTotalRenderCost, mTotalPhysicsCost, mTotalNetworkCost, mTotalSimulationCost; +}; + +struct SelectionQuota +{ + SelectionQuota( S32 localId, F32 renderCost, F32 physicsCost, F32 networkCost, F32 simulationCost ) + : mLocalId( localId) + , mRenderCost( renderCost ) + , mPhysicsCost( physicsCost ) + , mNetworkCost( networkCost ) + , mSimulationCost( simulationCost ) + { + } + SelectionQuota() {} + + F32 mRenderCost, mPhysicsCost, mNetworkCost, mSimulationCost; + S32 mLocalId; +}; + +#endif + + + diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index 0a4cd51ea0..e8cd871157 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -1348,3 +1348,12 @@ LLParcel::ECategory category_ui_string_to_category(const std::string& s) // is a distinct option from "None" and "Other" return LLParcel::C_ANY; } + +void LLParcel::updateQuota( const LLUUID& objectId, const ParcelQuota& quota ) +{ + if ( mID == objectId ) + { + mQuota = quota; + } +} + diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index 71b65d99ce..4893337967 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -34,7 +34,7 @@ #include "llpermissions.h" #include "lltimer.h" #include "v3math.h" - +#include "llaccountingquota.h" // Grid out of which parcels taken is stepped every 4 meters. const F32 PARCEL_GRID_STEP_METERS = 4.f; @@ -586,7 +586,11 @@ public: LLUUID getPreviousOwnerID() const { return mPreviousOwnerID; } BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; } BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; } - + + + void updateQuota( const LLUUID& objectId, const ParcelQuota& quota ); + const ParcelQuota& getQuota( void ) { return mQuota; } + protected: LLUUID mID; LLUUID mOwnerID; @@ -657,8 +661,9 @@ protected: BOOL mRegionPushOverride; BOOL mRegionDenyAnonymousOverride; BOOL mRegionDenyAgeUnverifiedOverride; - - + + ParcelQuota mQuota; + public: // HACK, make private S32 mLocalID; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index cbf22b75e8..769dcf8457 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -77,6 +77,7 @@ include_directories( set(viewer_SOURCE_FILES groupchatlistener.cpp + llaccountingquotamanager.cpp llagent.cpp llagentaccess.cpp llagentcamera.cpp @@ -626,6 +627,7 @@ set(viewer_HEADER_FILES CMakeLists.txt ViewerInstall.cmake groupchatlistener.h + llaccountingquotamanager.h llagent.h llagentaccess.h llagentcamera.h diff --git a/indra/newview/llaccountingquotamanager.cpp b/indra/newview/llaccountingquotamanager.cpp new file mode 100644 index 0000000000..ada74ea44c --- /dev/null +++ b/indra/newview/llaccountingquotamanager.cpp @@ -0,0 +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 "<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 "< +{ +public: + //Ctor + LLAccountingQuotaManager(); + //Store an object that will be eventually fetched + void updateObjectCost( const LLUUID& objectID ); + //Request quotas for object list + void fetchQuotas( const std::string& url ); + //Delete a specific object from the pending list + void removePendingObjectQuota( const LLUUID& objectID ); + +private: + //Set of objects that need to update their cost + std::set mUpdateObjectQuota; + //During fetchQuota we move object into a the pending set to signify that + //a fetch has been instigated. + std::set mPendingObjectQuota; + typedef std::set::iterator IDIt; +}; +//=============================================================================== + +#endif \ No newline at end of file diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 73c1f99fa0..061a42ab57 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -85,6 +85,7 @@ #include "llviewerwindow.h" #include "llvovolume.h" #include "lluictrlfactory.h" +#include "llaccountingquotamanager.h" // Globals LLFloaterTools *gFloaterTools = NULL; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index f5fee662e6..e7878d8adf 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -102,6 +102,7 @@ #include "lltrans.h" #include "llsdutil.h" #include "llmediaentry.h" +#include "llaccountingquota.h" //#define DEBUG_UPDATE_TYPE @@ -5702,3 +5703,10 @@ public: LLHTTPRegistration 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 21198f7dd1..a0ad52df6b 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -43,6 +43,7 @@ #include "v3dmath.h" #include "v3math.h" #include "llvertexbuffer.h" +#include "llaccountingquota.h" class LLAgent; // TODO: Get rid of this. class LLAudioSource; @@ -643,7 +644,11 @@ protected: 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 @@ -705,6 +710,8 @@ protected: F32 mPhysicsCost; F32 mLinksetPhysicsCost; + SelectionQuota mSelectionQuota; + bool mCostStale; mutable bool mPhysicsShapeUnknown; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index ab2e07e4df..007b3416f1 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1418,6 +1418,15 @@ void LLViewerObjectList::onObjectCostFetchFailure(const LLUUID& object_id) mPendingObjectCost.erase(object_id); } +void LLViewerObjectList::updateQuotaCost( const LLUUID& objectId, const SelectionQuota& quota ) +{ + LLViewerObject* pVO = findObject( objectId ); + if ( pVO ) + { + //pVO->updateQuota( quota ); + } +} + void LLViewerObjectList::updatePhysicsFlags(const LLViewerObject* object) { mStalePhysicsFlags.insert(object->getID()); diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 65374bca70..8e211eaf73 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -36,6 +36,7 @@ // project includes #include "llviewerobject.h" +#include "llaccountingquota.h" class LLCamera; class LLNetMap; @@ -101,6 +102,8 @@ public: F32 restitution, F32 gravity_multiplier); + void updateQuotaCost( const LLUUID& objectId, const SelectionQuota& costs ); + void shiftObjects(const LLVector3 &offset); bool hasMapObjectInRegion(LLViewerRegion* regionp) ; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index f835351c04..590c82856d 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1545,6 +1545,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); + //prep# Finalize these!!!!!!!!! + //capabilityNames.append("AccountingVO"); + capabilityNames.append("AccountingParcel"); + capabilityNames.append("AccountingRegion"); + // Please add new capabilities alphabetically to reduce // merge conflicts. @@ -1658,3 +1663,4 @@ std::string LLViewerRegion::getDescription() const { return stringize(*this); } + diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 9c5b85b77f..a6e5c47b86 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -275,6 +275,7 @@ public: F32 getLandHeightRegion(const LLVector3& region_pos); void getInfo(LLSD& info); + typedef enum { -- cgit v1.2.3 From cb3875fe72b120251c289302b958243e08a24e5b Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 12:00:58 -0400 Subject: SH-1527 FIXED Fix for black alpha objects with lighting and shadows enabled and no lights around. --- .../shaders/class1/deferred/alphaSkinnedV.glsl | 25 +++++++++++++--------- .../shaders/class1/deferred/alphaV.glsl | 25 +++++++++++++--------- .../shaders/class1/deferred/avatarAlphaV.glsl | 25 +++++++++++++--------- .../shaders/class2/deferred/alphaSkinnedV.glsl | 25 +++++++++++++--------- .../shaders/class2/deferred/alphaV.glsl | 25 +++++++++++++--------- .../shaders/class2/deferred/avatarAlphaV.glsl | 25 +++++++++++++--------- 6 files changed, 90 insertions(+), 60 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl index 5addbbb176..65d9209983 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl @@ -35,19 +35,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl index 525b68c437..2691fc8ded 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl @@ -36,19 +36,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl index a2a7dea20d..a012cb5030 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl @@ -35,19 +35,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl index d227346163..dfb36980b0 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl @@ -35,19 +35,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl index 86f014df35..f6160815eb 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl @@ -35,19 +35,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl index 495e86c8db..0ae09df0c6 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl @@ -37,19 +37,24 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //get distance float d = length(lv); - //normalize light vector - lv *= 1.0/d; + float da = 0.0; + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv *= 1.0/d; - //distance attenuation - float dist2 = d*d/(la*la); - float da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + //distance attenuation + float dist2 = d*d/(la*la); + da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 - //angular attenuation - da *= calcDirectionalLight(n, lv); + //angular attenuation + da *= calcDirectionalLight(n, lv); + } return da; } -- cgit v1.2.3 From 303a59e7bc8537a63aee42f738fff8a79049c2a2 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 14:16:56 -0400 Subject: dos2unix fixes for newview files. --- indra/newview/llaccountingquotamanager.cpp | 528 +- indra/newview/lldrawpoolbump.cpp | 6 +- indra/newview/llfeaturemanager.cpp | 1614 ++-- indra/newview/llfloaterbuyland.cpp | 18 +- indra/newview/llpanelobject.cpp | 3998 +++++----- indra/newview/llviewermessage.cpp | 8 +- indra/newview/llviewerobject.cpp | 11424 +++++++++++++-------------- indra/newview/llviewerobject.h | 1650 ++-- indra/newview/llviewerparcelmgr.cpp | 6 +- indra/newview/llviewerprecompiledheaders.h | 4 +- indra/newview/llviewertexturelist.cpp | 4 +- 11 files changed, 9630 insertions(+), 9630 deletions(-) (limited to 'indra') 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 "<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 "<removePendingObjectQuota( iter->asUUID() ); + } + } + + void error( U32 statusNum, const std::string& reason ) + { + llwarns << "Transport error "<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 "< -#include - -#include - -#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 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("\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 +#include + +#include + +#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 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("\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("checkbox locked"); - childSetCommitCallback("checkbox locked",onCommitLock,this); - - // Physical checkbox - mCheckPhysics = getChild("Physical Checkbox Ctrl"); - childSetCommitCallback("Physical Checkbox Ctrl",onCommitPhysics,this); - - // Temporary checkbox - mCheckTemporary = getChild("Temporary Checkbox Ctrl"); - childSetCommitCallback("Temporary Checkbox Ctrl",onCommitTemporary,this); - - // Phantom checkbox - mCheckPhantom = getChild("Phantom Checkbox Ctrl"); - childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); - - - // Position - mLabelPosition = getChild("label position"); - mCtrlPosX = getChild("Pos X"); - childSetCommitCallback("Pos X",onCommitPosition,this); - mCtrlPosY = getChild("Pos Y"); - childSetCommitCallback("Pos Y",onCommitPosition,this); - mCtrlPosZ = getChild("Pos Z"); - childSetCommitCallback("Pos Z",onCommitPosition,this); - - // Scale - mLabelSize = getChild("label size"); - mCtrlScaleX = getChild("Scale X"); - childSetCommitCallback("Scale X",onCommitScale,this); - - // Scale Y - mCtrlScaleY = getChild("Scale Y"); - childSetCommitCallback("Scale Y",onCommitScale,this); - - // Scale Z - mCtrlScaleZ = getChild("Scale Z"); - childSetCommitCallback("Scale Z",onCommitScale,this); - - // Rotation - mLabelRotation = getChild("label rotation"); - mCtrlRotX = getChild("Rot X"); - childSetCommitCallback("Rot X",onCommitRotation,this); - mCtrlRotY = getChild("Rot Y"); - childSetCommitCallback("Rot Y",onCommitRotation,this); - mCtrlRotZ = getChild("Rot Z"); - childSetCommitCallback("Rot Z",onCommitRotation,this); - - //-------------------------------------------------------- - - // Base Type - mComboBaseType = getChild("comboBaseType"); - childSetCommitCallback("comboBaseType",onCommitParametric,this); - - // Cut - mLabelCut = getChild("text cut"); - mSpinCutBegin = getChild("cut begin"); - childSetCommitCallback("cut begin",onCommitParametric,this); - mSpinCutBegin->setValidateBeforeCommit( precommitValidate ); - mSpinCutEnd = getChild("cut end"); - childSetCommitCallback("cut end",onCommitParametric,this); - mSpinCutEnd->setValidateBeforeCommit( &precommitValidate ); - - // Hollow / Skew - mLabelHollow = getChild("text hollow"); - mLabelSkew = getChild("text skew"); - mSpinHollow = getChild("Scale 1"); - childSetCommitCallback("Scale 1",onCommitParametric,this); - mSpinHollow->setValidateBeforeCommit( &precommitValidate ); - mSpinSkew = getChild("Skew"); - childSetCommitCallback("Skew",onCommitParametric,this); - mSpinSkew->setValidateBeforeCommit( &precommitValidate ); - mLabelHoleType = getChild("Hollow Shape"); - - // Hole Type - mComboHoleType = getChild("hole"); - childSetCommitCallback("hole",onCommitParametric,this); - - // Twist - mLabelTwist = getChild("text twist"); - mSpinTwistBegin = getChild("Twist Begin"); - childSetCommitCallback("Twist Begin",onCommitParametric,this); - mSpinTwistBegin->setValidateBeforeCommit( precommitValidate ); - mSpinTwist = getChild("Twist End"); - childSetCommitCallback("Twist End",onCommitParametric,this); - mSpinTwist->setValidateBeforeCommit( &precommitValidate ); - - // Scale - mSpinScaleX = getChild("Taper Scale X"); - childSetCommitCallback("Taper Scale X",onCommitParametric,this); - mSpinScaleX->setValidateBeforeCommit( &precommitValidate ); - mSpinScaleY = getChild("Taper Scale Y"); - childSetCommitCallback("Taper Scale Y",onCommitParametric,this); - mSpinScaleY->setValidateBeforeCommit( &precommitValidate ); - - // Shear - mLabelShear = getChild("text topshear"); - mSpinShearX = getChild("Shear X"); - childSetCommitCallback("Shear X",onCommitParametric,this); - mSpinShearX->setValidateBeforeCommit( &precommitValidate ); - mSpinShearY = getChild("Shear Y"); - childSetCommitCallback("Shear Y",onCommitParametric,this); - mSpinShearY->setValidateBeforeCommit( &precommitValidate ); - - // Path / Profile - mCtrlPathBegin = getChild("Path Limit Begin"); - childSetCommitCallback("Path Limit Begin",onCommitParametric,this); - mCtrlPathBegin->setValidateBeforeCommit( &precommitValidate ); - mCtrlPathEnd = getChild("Path Limit End"); - childSetCommitCallback("Path Limit End",onCommitParametric,this); - mCtrlPathEnd->setValidateBeforeCommit( &precommitValidate ); - - // Taper - mLabelTaper = getChild("text taper2"); - mSpinTaperX = getChild("Taper X"); - childSetCommitCallback("Taper X",onCommitParametric,this); - mSpinTaperX->setValidateBeforeCommit( precommitValidate ); - mSpinTaperY = getChild("Taper Y"); - childSetCommitCallback("Taper Y",onCommitParametric,this); - mSpinTaperY->setValidateBeforeCommit( precommitValidate ); - - // Radius Offset / Revolutions - mLabelRadiusOffset = getChild("text radius delta"); - mLabelRevolutions = getChild("text revolutions"); - mSpinRadiusOffset = getChild("Radius Offset"); - childSetCommitCallback("Radius Offset",onCommitParametric,this); - mSpinRadiusOffset->setValidateBeforeCommit( &precommitValidate ); - mSpinRevolutions = getChild("Revolutions"); - childSetCommitCallback("Revolutions",onCommitParametric,this); - mSpinRevolutions->setValidateBeforeCommit( &precommitValidate ); - - // Sculpt - mCtrlSculptTexture = getChild("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("label sculpt type"); - mCtrlSculptType = getChild("sculpt type control"); - childSetCommitCallback("sculpt type control", onCommitSculptType, this); - mCtrlSculptMirror = getChild("sculpt mirror control"); - childSetCommitCallback("sculpt mirror control", onCommitSculptType, this); - mCtrlSculptInvert = getChild("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("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& child_positions = mObject->mUnselectedChildrenPositions ; - std::vector 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("Scale X")->setMaxValue(max_scale); - getChild("Scale Y")->setMaxValue(max_scale); - getChild("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("sculpt texture control"); - - if (mTextureCtrl) - { - mSculptTextureRevert = mTextureCtrl->getImageAssetID(); - } - - sendSculpt(); -} - - -void LLPanelObject::onCommitSculpt( const LLSD& data ) -{ - sendSculpt(); -} - -BOOL LLPanelObject::onDropSculpt(LLInventoryItem* item) -{ - LLTextureCtrl* mTextureCtrl = getChild("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("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("checkbox locked"); + childSetCommitCallback("checkbox locked",onCommitLock,this); + + // Physical checkbox + mCheckPhysics = getChild("Physical Checkbox Ctrl"); + childSetCommitCallback("Physical Checkbox Ctrl",onCommitPhysics,this); + + // Temporary checkbox + mCheckTemporary = getChild("Temporary Checkbox Ctrl"); + childSetCommitCallback("Temporary Checkbox Ctrl",onCommitTemporary,this); + + // Phantom checkbox + mCheckPhantom = getChild("Phantom Checkbox Ctrl"); + childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); + + + // Position + mLabelPosition = getChild("label position"); + mCtrlPosX = getChild("Pos X"); + childSetCommitCallback("Pos X",onCommitPosition,this); + mCtrlPosY = getChild("Pos Y"); + childSetCommitCallback("Pos Y",onCommitPosition,this); + mCtrlPosZ = getChild("Pos Z"); + childSetCommitCallback("Pos Z",onCommitPosition,this); + + // Scale + mLabelSize = getChild("label size"); + mCtrlScaleX = getChild("Scale X"); + childSetCommitCallback("Scale X",onCommitScale,this); + + // Scale Y + mCtrlScaleY = getChild("Scale Y"); + childSetCommitCallback("Scale Y",onCommitScale,this); + + // Scale Z + mCtrlScaleZ = getChild("Scale Z"); + childSetCommitCallback("Scale Z",onCommitScale,this); + + // Rotation + mLabelRotation = getChild("label rotation"); + mCtrlRotX = getChild("Rot X"); + childSetCommitCallback("Rot X",onCommitRotation,this); + mCtrlRotY = getChild("Rot Y"); + childSetCommitCallback("Rot Y",onCommitRotation,this); + mCtrlRotZ = getChild("Rot Z"); + childSetCommitCallback("Rot Z",onCommitRotation,this); + + //-------------------------------------------------------- + + // Base Type + mComboBaseType = getChild("comboBaseType"); + childSetCommitCallback("comboBaseType",onCommitParametric,this); + + // Cut + mLabelCut = getChild("text cut"); + mSpinCutBegin = getChild("cut begin"); + childSetCommitCallback("cut begin",onCommitParametric,this); + mSpinCutBegin->setValidateBeforeCommit( precommitValidate ); + mSpinCutEnd = getChild("cut end"); + childSetCommitCallback("cut end",onCommitParametric,this); + mSpinCutEnd->setValidateBeforeCommit( &precommitValidate ); + + // Hollow / Skew + mLabelHollow = getChild("text hollow"); + mLabelSkew = getChild("text skew"); + mSpinHollow = getChild("Scale 1"); + childSetCommitCallback("Scale 1",onCommitParametric,this); + mSpinHollow->setValidateBeforeCommit( &precommitValidate ); + mSpinSkew = getChild("Skew"); + childSetCommitCallback("Skew",onCommitParametric,this); + mSpinSkew->setValidateBeforeCommit( &precommitValidate ); + mLabelHoleType = getChild("Hollow Shape"); + + // Hole Type + mComboHoleType = getChild("hole"); + childSetCommitCallback("hole",onCommitParametric,this); + + // Twist + mLabelTwist = getChild("text twist"); + mSpinTwistBegin = getChild("Twist Begin"); + childSetCommitCallback("Twist Begin",onCommitParametric,this); + mSpinTwistBegin->setValidateBeforeCommit( precommitValidate ); + mSpinTwist = getChild("Twist End"); + childSetCommitCallback("Twist End",onCommitParametric,this); + mSpinTwist->setValidateBeforeCommit( &precommitValidate ); + + // Scale + mSpinScaleX = getChild("Taper Scale X"); + childSetCommitCallback("Taper Scale X",onCommitParametric,this); + mSpinScaleX->setValidateBeforeCommit( &precommitValidate ); + mSpinScaleY = getChild("Taper Scale Y"); + childSetCommitCallback("Taper Scale Y",onCommitParametric,this); + mSpinScaleY->setValidateBeforeCommit( &precommitValidate ); + + // Shear + mLabelShear = getChild("text topshear"); + mSpinShearX = getChild("Shear X"); + childSetCommitCallback("Shear X",onCommitParametric,this); + mSpinShearX->setValidateBeforeCommit( &precommitValidate ); + mSpinShearY = getChild("Shear Y"); + childSetCommitCallback("Shear Y",onCommitParametric,this); + mSpinShearY->setValidateBeforeCommit( &precommitValidate ); + + // Path / Profile + mCtrlPathBegin = getChild("Path Limit Begin"); + childSetCommitCallback("Path Limit Begin",onCommitParametric,this); + mCtrlPathBegin->setValidateBeforeCommit( &precommitValidate ); + mCtrlPathEnd = getChild("Path Limit End"); + childSetCommitCallback("Path Limit End",onCommitParametric,this); + mCtrlPathEnd->setValidateBeforeCommit( &precommitValidate ); + + // Taper + mLabelTaper = getChild("text taper2"); + mSpinTaperX = getChild("Taper X"); + childSetCommitCallback("Taper X",onCommitParametric,this); + mSpinTaperX->setValidateBeforeCommit( precommitValidate ); + mSpinTaperY = getChild("Taper Y"); + childSetCommitCallback("Taper Y",onCommitParametric,this); + mSpinTaperY->setValidateBeforeCommit( precommitValidate ); + + // Radius Offset / Revolutions + mLabelRadiusOffset = getChild("text radius delta"); + mLabelRevolutions = getChild("text revolutions"); + mSpinRadiusOffset = getChild("Radius Offset"); + childSetCommitCallback("Radius Offset",onCommitParametric,this); + mSpinRadiusOffset->setValidateBeforeCommit( &precommitValidate ); + mSpinRevolutions = getChild("Revolutions"); + childSetCommitCallback("Revolutions",onCommitParametric,this); + mSpinRevolutions->setValidateBeforeCommit( &precommitValidate ); + + // Sculpt + mCtrlSculptTexture = getChild("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("label sculpt type"); + mCtrlSculptType = getChild("sculpt type control"); + childSetCommitCallback("sculpt type control", onCommitSculptType, this); + mCtrlSculptMirror = getChild("sculpt mirror control"); + childSetCommitCallback("sculpt mirror control", onCommitSculptType, this); + mCtrlSculptInvert = getChild("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("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& child_positions = mObject->mUnselectedChildrenPositions ; + std::vector 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("Scale X")->setMaxValue(max_scale); + getChild("Scale Y")->setMaxValue(max_scale); + getChild("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("sculpt texture control"); + + if (mTextureCtrl) + { + mSculptTextureRevert = mTextureCtrl->getImageAssetID(); + } + + sendSculpt(); +} + + +void LLPanelObject::onCommitSculpt( const LLSD& data ) +{ + sendSculpt(); +} + +BOOL LLPanelObject::onDropSculpt(LLInventoryItem* item) +{ + LLTextureCtrl* mTextureCtrl = getChild("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("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(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::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 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& 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& 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::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; paramsecond->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::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; paramunpackU16(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& 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 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 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 inv = new LLViewerInventoryItem; - inv->importLegacyStream(ifs); - mInventory->push_front(inv); - } - else if(0 == strcmp("inv_object", keyword)) - { - LLPointer 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 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 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 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 *new_images; - new_images = new LLPointer[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 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 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 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::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& 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& 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& rotations, - const std::vector& 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 - 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(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::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 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& 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& 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::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; paramsecond->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::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; paramunpackU16(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& 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 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 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 inv = new LLViewerInventoryItem; + inv->importLegacyStream(ifs); + mInventory->push_front(inv); + } + else if(0 == strcmp("inv_object", keyword)) + { + LLPointer 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 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 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 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 *new_images; + new_images = new LLPointer[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 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 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 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::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& 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& 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& rotations, + const std::vector& 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 + 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 - -#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 mExtraParameterList; - -public: - typedef std::list > child_list_t; - typedef std::list > 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& objects); - void addThisAndNonJointChildren(std::vector& 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& rotations, - const std::vector& positions) ; - void saveUnselectedChildrenRotation(std::vector& rotations) ; - void saveUnselectedChildrenPosition(std::vector& positions) ; - std::vector 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 *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 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 mText; - LLPointer 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& 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 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 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 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& verticesp, - LLStrider& normalsp, - LLStrider& texcoordsp, - LLStrider& colorsp, - LLStrider& 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 + +#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 mExtraParameterList; + +public: + typedef std::list > child_list_t; + typedef std::list > 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& objects); + void addThisAndNonJointChildren(std::vector& 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& rotations, + const std::vector& positions) ; + void saveUnselectedChildrenRotation(std::vector& rotations) ; + void saveUnselectedChildrenPosition(std::vector& positions) ; + std::vector 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 *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 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 mText; + LLPointer 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& 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 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 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 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& verticesp, + LLStrider& normalsp, + LLStrider& texcoordsp, + LLStrider& colorsp, + LLStrider& 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 -- cgit v1.2.3 From d5ae682e113d6a6f861b0d873a2fd061f8d03750 Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 16:04:36 -0400 Subject: SH-1444 FIXED "Allow mesh objects" setting is visible on non-mesh region. --- indra/newview/llfloaterregioninfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index fc6976755f..232b8e9096 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -592,7 +592,8 @@ bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region) const bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && gAgent.getRegion() && - !gAgent.getRegion()->getCapability("GetMesh").empty(); + !gAgent.getRegion()->getCapability("GetMesh").empty() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); getChildView("mesh_rez_enabled_check")->setVisible(enable_mesh); getChildView("mesh_rez_enabled_check")->setEnabled(getChildView("mesh_rez_enabled_check")->getEnabled() && enable_mesh); // Data gets filled in by processRegionInfo -- cgit v1.2.3 From 74da6623dcc53f440935ea69dde5cf140c9c5c4b Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 16:48:15 -0400 Subject: SH-1668 FIXED Cubes can be scaled to 64^3 --- indra/newview/llmanipscale.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra') diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 738d82e732..673f28e01f 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -93,6 +93,7 @@ F32 get_default_max_prim_scale(bool is_flora) if (gSavedSettings.getBOOL("MeshEnabled") && gAgent.getRegion() && !gAgent.getRegion()->getCapability("GetMesh").empty() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty() && !is_flora) { return DEFAULT_MAX_PRIM_SCALE; -- cgit v1.2.3 From 5a39eeb70fbc47a5a52f53e69ca5d95ed2f5e68a Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 16:52:26 -0400 Subject: SH-1669 FIXED Physics properties show up on DRTSIM-52 --- indra/newview/llpanelvolume.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index ebddaa90bc..7839cdd811 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -532,7 +532,8 @@ void LLPanelVolume::refresh() bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && gAgent.getRegion() && - !gAgent.getRegion()->getCapability("GetMesh").empty(); + !gAgent.getRegion()->getCapability("GetMesh").empty() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); getChildView("label physicsshapetype")->setVisible(enable_mesh); getChildView("Physics Shape Type Combo Ctrl")->setVisible(enable_mesh); -- cgit v1.2.3 From 7c042e1bcdde65da5629ed64a58ce1f3e23542be Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 16:58:31 -0400 Subject: SH-1467 WIP Viewer checks the wrong cap for mesh-ui disable Fixes that need to go into trunk because certain Mesh UI elements are showing up on DRTSIM-52. These fixes will probably be overwritten by the actual resolution of SH-1467 but I need this workaround now. --- indra/newview/llfloatertools.cpp | 5 +++-- indra/newview/llpanelobject.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 061a42ab57..edcb96314b 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -423,7 +423,7 @@ void LLFloaterTools::refresh() // Refresh object and prim count labels LLLocale locale(LLLocale::USER_LOCALE); - if ((gAgent.getRegion() && gAgent.getRegion()->getCapability("GetMesh").empty()) || !gSavedSettings.getBOOL("MeshEnabled")) + if ((gAgent.getRegion() && (gAgent.getRegion()->getCapability("GetMesh").empty() || gAgent.getRegion()->getCapability("ObjectAdd").empty())) || !gSavedSettings.getBOOL("MeshEnabled")) { std::string obj_count_string; LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount()); @@ -790,7 +790,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) bool show_mesh_cost = gAgent.getRegion() && !gAgent.getRegion()->getCapability("GetMesh").empty() && - gSavedSettings.getBOOL("MeshEnabled"); + gSavedSettings.getBOOL("MeshEnabled") && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); getChildView("obj_count")->setVisible( !land_visible && !show_mesh_cost); getChildView("prim_count")->setVisible( !land_visible && !show_mesh_cost); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 34a92cd0ac..b4d0ada196 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1742,7 +1742,8 @@ void LLPanelObject::refresh() bool enable_mesh = gSavedSettings.getBOOL("MeshEnabled") && gAgent.getRegion() && - !gAgent.getRegion()->getCapability("GetMesh").empty(); + !gAgent.getRegion()->getCapability("GetMesh").empty() && + !gAgent.getRegion()->getCapability("ObjectAdd").empty(); F32 max_scale = get_default_max_prim_scale(LLPickInfo::isFlora(mObject)); -- cgit v1.2.3 From 170de8330e3be55794878cefb53f62266c9a029d Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Thu, 26 May 2011 18:05:29 -0400 Subject: Added newline at end of header file to fix linux build. --- indra/newview/llaccountingquotamanager.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llaccountingquotamanager.h b/indra/newview/llaccountingquotamanager.h index 4c20561bce..9551df272c 100644 --- a/indra/newview/llaccountingquotamanager.h +++ b/indra/newview/llaccountingquotamanager.h @@ -57,4 +57,5 @@ private: }; //=============================================================================== -#endif \ No newline at end of file +#endif // LLACCOUNTINGQUOTAMANAGER + -- cgit v1.2.3