From 742ccdcf0c7e4ab6dd2cc73ba458e810c0a59a3d Mon Sep 17 00:00:00 2001 From: Lirusaito Date: Wed, 10 Jul 2013 06:30:19 -0400 Subject: [PATCH 1/3] Touched up awavefront once more to conform to permissions and be used as intended Added debug settings OBJExportNotifyFailed and OBJExportNotifySuccess for whether or not to notify about OBJ Exports failing or succeeding respectively Moved exports back into tools submenu, there's not enough variety to justify a menu dedicated to exportation Removed hardcoded "Insufficient Permissions" string, there's already a notification for this. Implemented proper permissions checking, along with own Avatar Export. --- indra/llappearance/llavatarappearance.h | 6 +- indra/llappearance/llavatarjointmesh.h | 5 +- .../newview/app_settings/settings_ascent.xml | 24 +++- indra/newview/awavefront.cpp | 70 ++++++++-- indra/newview/awavefront.h | 10 +- indra/newview/llviewermenu.cpp | 131 +----------------- .../default/xui/en-us/menu_pie_object.xml | 19 ++- .../skins/default/xui/en-us/menu_pie_self.xml | 3 + .../skins/default/xui/en-us/notifications.xml | 18 +-- 9 files changed, 105 insertions(+), 181 deletions(-) diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 2348f152b..b3a02e410 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -244,15 +244,11 @@ protected: virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority protected: + friend class WavefrontSaver; typedef std::multimap polymesh_map_t; polymesh_map_t mPolyMeshes; avatar_joint_list_t mMeshLOD; -// -public: - const virtual avatar_joint_list_t& getMeshLOD() const { return mMeshLOD; } -// - /** Meshes ** ** *******************************************************************************/ diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h index 90a0a5725..53b82c50a 100644 --- a/indra/llappearance/llavatarjointmesh.h +++ b/indra/llappearance/llavatarjointmesh.h @@ -62,6 +62,7 @@ public: class LLAvatarJointMesh : public virtual LLAvatarJoint { protected: + friend class WavefrontSaver; LLColor4 mColor; // color value // LLColor4 mSpecular; // specular color (always white for now) F32 mShiny; // shiny value @@ -131,10 +132,6 @@ public: void setIsTransparent(BOOL is_transparent) { mIsTransparent = is_transparent; } - // -public: - LLFace* getFace() { return mFace; } - // private: // Allocate skin data BOOL allocateSkinData( U32 numSkinJoints ); diff --git a/indra/newview/app_settings/settings_ascent.xml b/indra/newview/app_settings/settings_ascent.xml index e60c658c2..d5c0fd2e3 100644 --- a/indra/newview/app_settings/settings_ascent.xml +++ b/indra/newview/app_settings/settings_ascent.xml @@ -642,6 +642,28 @@ Value 0 + OBJExportNotifyFailed + + Comment + Show a notification when exporting to OBJ fails (both partially and completely) + Persist + 1 + Type + Boolean + Value + 1 + + OBJExportNotifySuccess + + Comment + Show a notification when exporting to OBJ succeeds + Persist + 1 + Type + Boolean + Value + 1 + OBJExportSwapYZ Comment @@ -653,5 +675,5 @@ Value 0 - + diff --git a/indra/newview/awavefront.cpp b/indra/newview/awavefront.cpp index d4cc49520..d48bb8dfa 100644 --- a/indra/newview/awavefront.cpp +++ b/indra/newview/awavefront.cpp @@ -1,7 +1,7 @@ /** * @file awavefront.cpp * @brief A system which allows saving in-world objects to Wavefront .OBJ files for offline texturizing/shading. - * @author Apelsin + * @authors Apelsin, Lirusaito * * $LicenseInfo:firstyear=2011&license=LGPLV3$ * Copyright (C) 2011-2013 Apelsin @@ -27,13 +27,14 @@ // library includes #include "aifilepicker.h" +#include "llnotificationsutil.h" // newview includes +#include "lfsimfeaturehandler.h" #include "llavatarappearancedefines.h" #include "llface.h" #include "llvoavatar.h" - -typedef std::vector avatar_joint_list_t; +#include "llvovolume.h" // menu includes #include "llevent.h" @@ -42,7 +43,10 @@ typedef std::vector avatar_joint_list_t; #include "llselectmgr.h" LLVOAvatar* find_avatar_from_object(LLViewerObject* object); +extern LLUUID gAgentID; +//Typedefs used in other files, using here for consistency. +typedef std::vector avatar_joint_list_t; typedef LLMemberListener view_listener_t; namespace @@ -57,6 +61,8 @@ namespace { wfsaver->saveFile(fp); llinfos << "OBJ file saved to " << selected_filename << llendl; + if (gSavedSettings.getBOOL("OBJExportNotifySuccess")) + LLNotificationsUtil::add("WavefrontExportSuccess", LLSD().with("FILENAME", selected_filename)); fclose(fp); } else llerrs << "can't open: " << selected_filename << llendl; @@ -192,22 +198,42 @@ void WavefrontSaver::Add(const LLViewerObject* some_vo) normfix.setRotation(v_form.getRotation()); //Should work... Add(some_vo->getVolume(), &v_form, &normfix); } - namespace { - class LLSaveSelectedObjects : public view_listener_t + bool can_export_node(const LLSelectNode* node) + { + if (const LLPermissions* perms = node->mPermissions) + { + if (!(gAgentID == perms->getCreator() || (LFSimFeatureHandler::instance().simSupportsExport() && gAgentID == perms->getOwner() && perms->getMaskEveryone() & PERM_EXPORT))) + { + static const LLCachedControl notify("OBJExportNotifyFailed", false); + if (notify) LLNotificationsUtil::add("WavefrontExportPartial", LLSD().with("OBJECT", node->mName)); + } + else return true; + } + return false; + } + class LFSaveSelectedObjects : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { if (LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection()) { - WavefrontSaver* wfsaver = new WavefrontSaver; //deleted in callback + WavefrontSaver* wfsaver = new WavefrontSaver; // deleted in callback wfsaver->offset = -selection->getFirstRootObject()->getRenderPosition(); for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end(); ++iter) { LLSelectNode* node = *iter; + if (!can_export_node(node)) continue; wfsaver->Add(node->getObject()); } + if (wfsaver->obj_v.empty()) + { + if (gSavedSettings.getBOOL("OBJExportNotifyFailed")) + LLNotificationsUtil::add("ExportFailed"); + delete wfsaver; + return true; + } AIFilePicker* filepicker = AIFilePicker::create(); filepicker->open(selection->getFirstNode()->mName.c_str()+OBJ); @@ -221,7 +247,7 @@ namespace void WavefrontSaver::Add(const LLVOAvatar* av_vo) //adds attachments, too! { offset = -av_vo->getRenderPosition(); - avatar_joint_list_t vjv = av_vo->getMeshLOD(); + avatar_joint_list_t vjv = av_vo->mMeshLOD; for (avatar_joint_list_t::const_iterator itervj = vjv.begin(); itervj != vjv.end(); ++itervj) { const LLViewerJoint* vj = dynamic_cast(*itervj); @@ -231,7 +257,7 @@ void WavefrontSaver::Add(const LLVOAvatar* av_vo) //adds attachments, too! if (!vjm) continue; vjm->updateJointGeometry(); - LLFace* face = vjm->getFace(); + LLFace* face = vjm->mFace; if (!face) continue; //Beware: this is a hack because LLFace has multiple LODs @@ -271,6 +297,11 @@ void WavefrontSaver::Add(const LLVOAvatar* av_vo) //adds attachments, too! { const LLViewerObject* c = *iterc; if (!c) continue; + if (const LLSelectNode* n = LLSelectMgr::getInstance()->getSelection()->findNode(const_cast(c))) + { + if (!can_export_node(n)) continue; + } + else continue; const LLVolume* vol = c->getVolume(); if (!vol) continue; @@ -293,17 +324,28 @@ void WavefrontSaver::Add(const LLVOAvatar* av_vo) //adds attachments, too! } } } - namespace { - class LLSaveSelectedAvatar : public view_listener_t + class LFSaveSelectedAvatar : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { if (const LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject())) { - WavefrontSaver* wfsaver = new WavefrontSaver; //deleted in callback + if (!avatar->isSelf()) + { + if (gSavedSettings.getBOOL("OBJExportNotifyFailed")) LLNotificationsUtil::add("ExportFailed"); + return true; + } + WavefrontSaver* wfsaver = new WavefrontSaver; // deleted in callback wfsaver->Add(avatar); + if (wfsaver->obj_v.empty()) + { + if (gSavedSettings.getBOOL("OBJExportNotifyFailed")) + LLNotificationsUtil::add("ExportFailed"); + delete wfsaver; + return true; + } AIFilePicker* filepicker = AIFilePicker::create(); filepicker->open(avatar->getFullname()+OBJ); @@ -383,9 +425,9 @@ bool WavefrontSaver::saveFile(LLFILE* fp) } void addMenu(view_listener_t* menu, const std::string& name); -void add_wave_listeners() //Called in llviewermenu with other addMenu calls, function linked against +void add_wave_listeners() // Called in llviewermenu with other addMenu calls, function linked against { - addMenu(new LLSaveSelectedObjects(), "Object.SaveAsOBJ"); - addMenu(new LLSaveSelectedAvatar(), "Avatar.SaveAsOBJ"); + addMenu(new LFSaveSelectedObjects(), "Object.SaveAsOBJ"); + addMenu(new LFSaveSelectedAvatar(), "Avatar.SaveAsOBJ"); } diff --git a/indra/newview/awavefront.h b/indra/newview/awavefront.h index f97099cd1..3f58ee4a0 100644 --- a/indra/newview/awavefront.h +++ b/indra/newview/awavefront.h @@ -1,7 +1,7 @@ /** * @file awavefront.h * @brief A system which allows saving in-world objects to Wavefront .OBJ files for offline texturizing/shading. - * @author Apelsin + * @authors Apelsin, Lirusaito * * $LicenseInfo:firstyear=2011&license=LGPLV3$ * Copyright (C) 2011-2013 Apelsin @@ -24,14 +24,6 @@ #ifndef AWAVEFRONT #define AWAVEFRONT -#include -#include "v3math.h" -#include "v2math.h" -#include "llface.h" -#include "llvolume.h" - -using namespace std; - class LLFace; class LLPolyMesh; class LLViewerObject; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 69bcbb308..fcafd4bfd 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -171,7 +171,6 @@ #include "shfloatermediaticker.h" #include "llpacketring.h" #include "aihttpview.h" -#include "awavefront.h" // #include "scriptcounter.h" @@ -225,6 +224,7 @@ void handle_test_load_url(void*); class AIHTTPView; +void add_wave_listeners(); //extern BOOL gHideSelectedObjects; //extern BOOL gAllowSelectAvatar; //extern BOOL gDebugAvatarRotation; @@ -489,11 +489,6 @@ void handle_mesh_save_obj(void*); void handle_mesh_load_obj(void*); void handle_morph_save_obj(void*); void handle_morph_load_obj(void*); -void save_avatar_to_obj(LLVOAvatar *avatar); -void save_selected_avatar_to_obj(); -void save_selected_objects_to_obj(); -void save_wavefront_continued(WavefrontSaver* wfsaver, AIFilePicker* filepicker); -void handle_save_current_avatar_obj(void*); void handle_debug_avatar_textures(void*); void handle_dump_region_object_cache(void*); @@ -706,8 +701,6 @@ void init_menus() gAttachSubMenu = gMenuBarView->getChildMenuByName("Attach Object", TRUE); gDetachSubMenu = gMenuBarView->getChildMenuByName("Detach Object", TRUE); - LLMenuGL*menu; - // // Add in the pose stand ------------------------------------------- /*LLMenuGL* sub = new LLMenuGL("Pose Stand..."); @@ -722,6 +715,9 @@ void init_menus() sub->addChild(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, NULL)); // ------------------------------------------------------*/ + // TomY TODO convert these two + LLMenuGL*menu; + menu = new LLMenuGL(CLIENT_MENU_NAME); menu->setCanTearOff(TRUE); init_client_menu(menu); @@ -6137,24 +6133,6 @@ class LLAvatarInviteToGroup : public view_listener_t } }; -class LLAvatarSaveAsOBJ : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - save_selected_avatar_to_obj(); - return true; - } -}; - -class LLSelectionSaveAsOBJ : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - save_selected_objects_to_obj(); - return true; - } -}; - class LLAvatarAddFriend : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -8538,104 +8516,6 @@ static void handle_morph_load_obj_continued(void* data, AIFilePicker* filepicker morph_data->setMorphFromMesh(&mesh); } -void handle_save_current_avatar_obj(void* data) -{ - if(gAgentAvatarp) - save_avatar_to_obj(gAgentAvatarp); -} - -void save_selected_avatar_to_obj() -{ - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - save_avatar_to_obj(avatar); -} - -void save_avatar_to_obj(LLVOAvatar *avatar) -{ - std::string file_name = llformat("%s.obj", avatar->getFullname().c_str()); - std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_NONE, file_name); - - WavefrontSaver* wfsaver = new WavefrontSaver(); - wfsaver->Add((LLVOAvatar*)avatar); - - AIFilePicker* filepicker = AIFilePicker::create(); - filepicker->open(full_path); - filepicker->run(boost::bind(&save_wavefront_continued, wfsaver, filepicker)); -} - -void save_selected_objects_to_obj() -{ - struct ff : public LLSelectedNodeFunctor - { - virtual bool apply(LLSelectNode* node) - { - return LLObjectBackup::getInstance()->validatePerms(node->mPermissions); - } - } func; - - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - - if(!selection) - return; - - if (!selection->applyToNodes(&func, false)) - { - llwarns << "Incorrect permissions: Wavefront OBJ export aborted" << llendl; - LLSD args; - args["REASON"] = "Insufficient Permissions"; - LLNotificationsUtil::add("WavefrontExportFailed", args); - return; - } - - std::string file_name = llformat("%s.obj", selection->getFirstNode()->mName.c_str()); - std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_NONE, file_name); - - WavefrontSaver* wfsaver = new WavefrontSaver(); - LLSelectNode* root_one = (LLSelectNode *)*selection->root_begin(); - wfsaver->offset = -root_one->getObject()->getRenderPosition(); - for (LLObjectSelection::iterator iter = selection->begin(); - iter != selection->end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - wfsaver->Add(object); - } - - AIFilePicker* filepicker = AIFilePicker::create(); - filepicker->open(full_path); - filepicker->run(boost::bind(&save_wavefront_continued, wfsaver, filepicker)); -} - -void save_wavefront_continued(WavefrontSaver* wfsaver, AIFilePicker* filepicker) -{ - if (!filepicker->hasFilename()) - { - llwarns << "No file; bailing" << llendl; - return; - } - std::string selected_filename = filepicker->getFilename(); - LLFILE* fp = LLFile::fopen(selected_filename, "wb"); - if (!fp) - { - llerrs << "can't open: " << selected_filename << llendl; - return; - } - try - { - wfsaver->saveFile(fp); - } - catch(int e) - { - llwarns << "An exception occurred while generating / saving OBJ file. Exception #" << e << llendl; - } - llinfos << "OBJ file saved to " << selected_filename << llendl; - LLSD args; - args["FILENAME"] = selected_filename; - LLNotificationsUtil::add("WavefrontExportSuccess", args); - fclose(fp); -} - // Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. // Returns NULL on failure. LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) @@ -9509,7 +9389,6 @@ void initialize_menus() addMenu(new LLAvatarEnableFreezeEject(), "Avatar.EnableFreezeEject"); addMenu(new LLAvatarCopyUUID(), "Avatar.CopyUUID"); addMenu(new LLAvatarClientUUID(), "Avatar.ClientID"); - addMenu(new LLAvatarSaveAsOBJ(), "Avatar.SaveAsOBJ"); // Object pie menu addMenu(new LLObjectOpen(), "Object.Open"); @@ -9529,6 +9408,7 @@ void initialize_menus() addMenu(new LLPowerfulWizard(), "Object.Explode"); addMenu(new LLCanIHasKillEmAll(), "Object.EnableDestroy"); addMenu(new LLOHGOD(), "Object.EnableExplode"); + add_wave_listeners(); // addMenu(new LLObjectMute(), "Object.Mute"); addMenu(new LLObjectBuy(), "Object.Buy"); @@ -9541,7 +9421,6 @@ void initialize_menus() addMenu(new LLObjectExport(), "Object.Export"); addMenu(new LLObjectImport(), "Object.Import"); addMenu(new LLObjectImportUpload(), "Object.ImportUpload"); - addMenu(new LLSelectionSaveAsOBJ(), "Object.SaveAsOBJ"); addMenu(new LLObjectEnableOpen(), "Object.EnableOpen"); diff --git a/indra/newview/skins/default/xui/en-us/menu_pie_object.xml b/indra/newview/skins/default/xui/en-us/menu_pie_object.xml index a3015ed48..75fba2a28 100644 --- a/indra/newview/skins/default/xui/en-us/menu_pie_object.xml +++ b/indra/newview/skins/default/xui/en-us/menu_pie_object.xml @@ -60,20 +60,17 @@ + + + + + + + + - - - - - diff --git a/indra/newview/skins/default/xui/en-us/menu_pie_self.xml b/indra/newview/skins/default/xui/en-us/menu_pie_self.xml index d787e16e0..96c845e00 100644 --- a/indra/newview/skins/default/xui/en-us/menu_pie_self.xml +++ b/indra/newview/skins/default/xui/en-us/menu_pie_self.xml @@ -119,4 +119,7 @@ + + + diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml index 0849f9b4d..d6f8d4b34 100644 --- a/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/indra/newview/skins/default/xui/en-us/notifications.xml @@ -9638,21 +9638,17 @@ Would you like to enable announcing keys to objects in the sim? -Export to Wavefront OBJ file failed: - -[REASON] + icon="notify.tga" + name="WavefrontExportPartial" + type="notify"> +Unable to include [OBJECT] in export, insufficient permissions. -Object successfully exported in Wavefront OBJ format to: - -[FILENAME] + type="notifytip"> +Object successfully exported to: [FILENAME] From 7e874d7d56084f42061e5d216dfe685826b70932 Mon Sep 17 00:00:00 2001 From: Lirusaito Date: Wed, 10 Jul 2013 07:35:50 -0400 Subject: [PATCH 2/3] Fix Issue 931: When viewing the profile of a muted avatar, the Mute button should be changed to Unmute --- indra/newview/llpanelavatar.cpp | 22 +------------------ indra/newview/llpanelavatar.h | 13 ----------- .../skins/default/xui/en-us/panel_avatar.xml | 4 ++-- 3 files changed, 3 insertions(+), 36 deletions(-) diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 26e2f356f..85845e7f0 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -520,7 +520,7 @@ BOOL LLPanelAvatarSecondLife::postBuild(void) getChild("Add Friend...")->setCommitCallback(boost::bind(LLAvatarActions::requestFriendshipDialog, boost::bind(&LLPanelAvatar::getAvatarID, pa))); getChild("Pay...")->setCommitCallback(boost::bind(LLAvatarActions::pay, boost::bind(&LLPanelAvatar::getAvatarID, pa))); - childSetAction("Mute", LLPanelAvatar::onClickMute, pa); + getChild("Mute")->setCommitCallback(boost::bind(LLAvatarActions::toggleBlock, boost::bind(&LLPanelAvatar::getAvatarID, pa))); getChild("Offer Teleport...")->setCommitCallback(boost::bind(static_cast(LLAvatarActions::offerTeleport), boost::bind(&LLPanelAvatar::getAvatarID, pa))); @@ -1727,26 +1727,6 @@ void LLPanelAvatar::onClickGetKey(void *userdata) gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(agent_id.asString())); } -//----------------------------------------------------------------------------- -// onClickMute() -//----------------------------------------------------------------------------- -void LLPanelAvatar::onClickMute(void *userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - - LLUUID agent_id = self->getAvatarID(); - - LLFloaterMute::showInstance(); - if (LLAvatarActions::isBlocked(agent_id)) - { - LLFloaterMute::getInstance()->selectMute(agent_id); - } - else - { - LLAvatarActions::toggleBlock(agent_id); - } -} - // static void LLPanelAvatar::onClickOK(void *userdata) { diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index ef9841992..a7c18e796 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -40,23 +40,11 @@ #include "llavatarpropertiesprocessor.h" class LLAvatarName; -class LLButton; class LLCheckBoxCtrl; -class LLDropTarget; -class LLInventoryItem; class LLLineEditor; -class LLNameEditor; class LLPanelAvatar; -class LLScrollListCtrl; class LLTabContainer; -class LLTextBox; -class LLTextEditor; -class LLTextureCtrl; -class LLUICtrl; -class LLViewerTexture; class LLViewerObject; -class LLMessageSystem; -class LLIconCtrl; class LLMediaCtrl; class LLPanelPick; @@ -328,7 +316,6 @@ public: static void onClickGetKey(void *userdata); static void onClickOK( void *userdata); static void onClickCancel( void *userdata); - static void onClickMute( void *userdata); private: void enableOKIfReady(); diff --git a/indra/newview/skins/default/xui/en-us/panel_avatar.xml b/indra/newview/skins/default/xui/en-us/panel_avatar.xml index 3637ee8af..c4d6f0f97 100644 --- a/indra/newview/skins/default/xui/en-us/panel_avatar.xml +++ b/indra/newview/skins/default/xui/en-us/panel_avatar.xml @@ -183,8 +183,8 @@ label="Instant Message..." label_selected="Instant Message..." left_delta="71" mouse_opaque="true" name="Instant Message..." tool_tip="Instant Message (IM)" width="140" /> -