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/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 65451b34a..cd68a3f8a 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -932,7 +932,6 @@ P2(groupMemberDataResponder, transfer_300s); P2(groupProposalBallotResponder, transfer_300s); P(homeLocationResponder); P2(HTTPGetResponder, reply_15s); -P(iamHereLogin); P(iamHere); P(iamHereVoice); P2(inventoryModelFetchDescendentsResponder, transfer_300s); 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/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/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 3abb4c2b2..cbd78eb9e 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -90,9 +90,6 @@ #include "llstring.h" #include -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy iamHereLogin_timeout; - const S32 BLACK_BORDER_HEIGHT = 160; const S32 MAX_PASSWORD = 16; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 7a79e3dc8..a271f8a6b 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] 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" /> -