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.
This commit is contained in:
Lirusaito
2013-07-10 06:30:19 -04:00
parent 8e503f2596
commit 742ccdcf0c
9 changed files with 105 additions and 181 deletions

View File

@@ -244,15 +244,11 @@ protected:
virtual void dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority
protected:
friend class WavefrontSaver;
typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
polymesh_map_t mPolyMeshes;
avatar_joint_list_t mMeshLOD;
// <edit>
public:
const virtual avatar_joint_list_t& getMeshLOD() const { return mMeshLOD; }
// </edit>
/** Meshes
** **
*******************************************************************************/

View File

@@ -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; }
// <edit>
public:
LLFace* getFace() { return mFace; }
// </edit>
private:
// Allocate skin data
BOOL allocateSkinData( U32 numSkinJoints );

View File

@@ -642,6 +642,28 @@
<key>Value</key>
<boolean>0</boolean>
</map>
<key>OBJExportNotifyFailed</key>
<map>
<key>Comment</key>
<string>Show a notification when exporting to OBJ fails (both partially and completely)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OBJExportNotifySuccess</key>
<map>
<key>Comment</key>
<string>Show a notification when exporting to OBJ succeeds</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OBJExportSwapYZ</key>
<map>
<key>Comment</key>
@@ -653,5 +675,5 @@
<key>Value</key>
<integer>0</integer>
</map>
</map>
</map>
</llsd>

View File

@@ -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<LLAvatarJoint*> avatar_joint_list_t;
#include "llvovolume.h"
// menu includes
#include "llevent.h"
@@ -42,7 +43,10 @@ typedef std::vector<LLAvatarJoint*> 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<LLAvatarJoint*> avatar_joint_list_t;
typedef LLMemberListener<LLView> 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<bool> 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<LLOldEvents::LLEvent> 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<LLViewerJoint*>(*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<LLViewerObject*>(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<LLOldEvents::LLEvent> 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");
}

View File

@@ -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 <vector>
#include "v3math.h"
#include "v2math.h"
#include "llface.h"
#include "llvolume.h"
using namespace std;
class LLFace;
class LLPolyMesh;
class LLViewerObject;

View File

@@ -171,7 +171,6 @@
#include "shfloatermediaticker.h"
#include "llpacketring.h"
#include "aihttpview.h"
#include "awavefront.h"
// </edit>
#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;
// <dogmode>
// 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));
// </dogmode> ------------------------------------------------------*/
// 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<LLEvent> event, const LLSD& userdata)
{
save_selected_avatar_to_obj();
return true;
}
};
class LLSelectionSaveAsOBJ : public view_listener_t
{
bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
{
save_selected_objects_to_obj();
return true;
}
};
class LLAvatarAddFriend : public view_listener_t
{
bool handleEvent(LLPointer<LLEvent> 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();
// </edit>
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");

View File

@@ -60,20 +60,17 @@
<menu_item_call enabled="true" hidden="false" label="Data" mouse_opaque="true" name="Data">
<on_click function="Object.Data" />
</menu_item_call>
<menu_item_call label="Export" mouse_opaque="true" name="Export">
<on_click function="Object.Export" />
<on_enable function="Object.EnableExport" />
</menu_item_call>
<menu_item_call label="Save OBJ..." mouse_opaque="true" name="Save OBJ...">
<on_click function="Object.SaveAsOBJ" />
<on_enable function="Object.EnableExport" />
</menu_item_call>
<menu_item_call enabled="true" label="Reload" mouse_opaque="true" name="Reload Textures">
<on_click function="Object.ReloadTextures" />
</menu_item_call>
<menu_item_separator />
<pie_menu label="Export &gt;" name="Export Menu">
<menu_item_call enabled="false" hidden="false" label="XML" mouse_opaque="true" name="ExportXML">
<on_click function="Object.Export" />
<on_enable function="Object.EnableExport" />
</menu_item_call>
<menu_item_call enabled="false" hidden="false" label="Wavefront" mouse_opaque="true" name="ExportOBJ">
<on_click function="Object.SaveAsOBJ" />
<on_enable function="Object.EnableExport" />
</menu_item_call>
</pie_menu>
</pie_menu>
<menu_item_call enabled="false" label="Mute" mouse_opaque="true" name="Object Mute">
<on_click function="Object.Mute" />

View File

@@ -119,4 +119,7 @@
<on_click function="ShowFloater" userdata="appearance" />
<on_enable function="Edit.EnableCustomizeAvatar" />
</menu_item_call>
<menu_item_call label="Save OBJ..." mouse_opaque="true" name="Save OBJ...">
<on_click function="Avatar.SaveAsOBJ" />
</menu_item_call>
</pie_menu>

View File

@@ -9638,21 +9638,17 @@ Would you like to enable announcing keys to objects in the sim?
</notification>
<notification
icon="alert.tga"
name="WavefrontExportFailed"
type="alert">
Export to Wavefront OBJ file failed:
[REASON]
icon="notify.tga"
name="WavefrontExportPartial"
type="notify">
Unable to include [OBJECT] in export, insufficient permissions.
</notification>
<notification
icon="notify.tga"
icon="notifytip.tga"
name="WavefrontExportSuccess"
type="notify">
Object successfully exported in Wavefront OBJ format to:
[FILENAME]
type="notifytip">
Object successfully exported to: [FILENAME]
</notification>
</notifications>