Add wearable exporting / importing in linden_genepool format.
As importing has been broken for a long time, I decided to hijack the existing (broken) buttons of the Appearance floater for the following new implementation: The currently selected wearable, if full perm and the agent is owner (of course) and creator, then that wearable can be exported to disk with AIFilePicker in the context "archetype". The used format is now XML, linden_genepool version 1.0, the same format that is used when saving from Advanced --> Character --> Character Tests --> Appearance to XML in any viewer. However, unlike that Advanced option (which normally only works when DebugAvatarAppearanceMessage is set to TRUE, ie in the official Linden Viewer; but that does a lot more, most likely unwanted things: it causes to dump files in this format to the LL_PATH_LOGS directory whenever appearance data comes by and other stuff for debugging purposes only), now ONLY the selected wearable is written to the file. In the case of multiwear with several layers, that means the selected layer, as well. When importing these XML files again, only the selected wearable/layer is overwritten (assuming it is modifiable) with the data in the file that corresponds to that wearable (if the file contains data of another wearable then nothing happens). Note that this file format can be read by blender-avastar: Using this feature to save the shape you created in SL will allow you to import that into blender. Likewise, a shape created or modified in blender can be imported into SL using this feature.
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
#include "llvisualparam.h"
|
#include "llvisualparam.h"
|
||||||
#include "llavatarappearancedefines.h"
|
#include "llavatarappearancedefines.h"
|
||||||
#include "llwearable.h"
|
#include "llwearable.h"
|
||||||
|
#include "lldate.h"
|
||||||
|
|
||||||
using namespace LLAvatarAppearanceDefines;
|
using namespace LLAvatarAppearanceDefines;
|
||||||
|
|
||||||
@@ -68,47 +69,42 @@ LLAssetType::EType LLWearable::getAssetType() const
|
|||||||
return LLWearableType::getAssetType(mType);
|
return LLWearableType::getAssetType(mType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reX: new function
|
extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value);
|
||||||
BOOL LLWearable::FileExportParams( FILE* file ) const
|
|
||||||
|
// Replace '--' with '- -', see http://en.wikipedia.org/wiki/XML#Comments
|
||||||
|
std::string XMLCommentEscape(std::string const& comment)
|
||||||
{
|
{
|
||||||
// wearable type
|
std::string result = comment;
|
||||||
S32 type = (S32)mType;
|
std::string::size_type off = std::string::npos;
|
||||||
fprintf( file, "type %d\n", type );
|
while ((off = result.rfind("--", off)) != std::string::npos)
|
||||||
|
|
||||||
// parameters
|
|
||||||
S32 num_parameters = mVisualParamIndexMap.size();
|
|
||||||
fprintf( file, "parameters %d\n", num_parameters );
|
|
||||||
|
|
||||||
for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin();
|
|
||||||
iter != mVisualParamIndexMap.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
S32 param_id = iter->first;
|
result.replace(off, 2, "- -");
|
||||||
F32 param_weight = iter->second->getWeight();
|
|
||||||
fprintf( file, "%d %s\n", param_id, terse_F32_to_string(param_weight).c_str() );
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reX: new function
|
void LLWearable::archetypeExport(LLAPRFile& file) const
|
||||||
BOOL LLWearable::FileExportTextures( FILE* file ) const
|
|
||||||
{
|
{
|
||||||
// wearable type
|
apr_file_t* fp = file.getFileHandle();
|
||||||
S32 type = (S32)mType;
|
|
||||||
fprintf( file, "type %d\n", type );
|
|
||||||
|
|
||||||
// texture entries
|
apr_file_printf(fp, "\n\t\t<!-- wearable: %s -->\n", getTypeName().c_str());
|
||||||
S32 num_textures = mTEMap.size();
|
apr_file_printf(fp, "\t\t<!-- Name : %s -->\n", XMLCommentEscape(mName).c_str());
|
||||||
fprintf( file, "textures %d\n", num_textures );
|
apr_file_printf(fp, "\t\t<!-- Description: %s -->\n", XMLCommentEscape(mDescription).c_str());
|
||||||
|
apr_file_printf(fp, "\t\t<!-- date: %s -->\n", LLDate::now().asString().c_str());
|
||||||
|
|
||||||
for (te_map_t::const_iterator iter = mTEMap.begin();
|
for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter)
|
||||||
iter != mTEMap.end(); ++iter)
|
{
|
||||||
|
LLVisualParam const* param = iter->second;
|
||||||
|
dump_visual_param(file, param, param->getWeight());
|
||||||
|
}
|
||||||
|
for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter)
|
||||||
{
|
{
|
||||||
S32 te = iter->first;
|
S32 te = iter->first;
|
||||||
fprintf( file, "%d %s\n", te, iter->second->getID().asString().c_str() );
|
LLUUID const& image_id = iter->second->getID();
|
||||||
|
apr_file_printf(fp, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, image_id.asString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
apr_file_printf(fp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL LLWearable::exportFile(LLFILE* fp) const
|
BOOL LLWearable::exportFile(LLFILE* fp) const
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include "llwearabletype.h"
|
#include "llwearabletype.h"
|
||||||
#include "lllocaltextureobject.h"
|
#include "lllocaltextureobject.h"
|
||||||
|
|
||||||
|
class LLAPRFile;
|
||||||
class LLMD5;
|
class LLMD5;
|
||||||
class LLVisualParam;
|
class LLVisualParam;
|
||||||
class LLTexGlobalColorInfo;
|
class LLTexGlobalColorInfo;
|
||||||
@@ -77,8 +78,7 @@ public:
|
|||||||
|
|
||||||
virtual void writeToAvatar(LLAvatarAppearance* avatarp);
|
virtual void writeToAvatar(LLAvatarAppearance* avatarp);
|
||||||
|
|
||||||
BOOL FileExportParams(FILE* file) const;
|
void archetypeExport(LLAPRFile& file) const;
|
||||||
BOOL FileExportTextures(FILE* file) const;
|
|
||||||
|
|
||||||
enum EImportResult
|
enum EImportResult
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4439,7 +4439,7 @@ void LLAgent::requestLeaveGodMode()
|
|||||||
sendReliableMessage();
|
sendReliableMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value);
|
extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value);
|
||||||
extern std::string get_sequential_numbered_file_name(const std::string& prefix,
|
extern std::string get_sequential_numbered_file_name(const std::string& prefix,
|
||||||
const std::string& suffix);
|
const std::string& suffix);
|
||||||
|
|
||||||
@@ -4465,7 +4465,7 @@ void LLAgent::dumpSentAppearance(const std::string& dump_prefix)
|
|||||||
if (appearance_version_param)
|
if (appearance_version_param)
|
||||||
{
|
{
|
||||||
F32 value = appearance_version_param->getWeight();
|
F32 value = appearance_version_param->getWeight();
|
||||||
dump_visual_param(file, appearance_version_param, value);
|
dump_visual_param(outfile, appearance_version_param, value);
|
||||||
}
|
}
|
||||||
for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
|
for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
|
||||||
iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
|
iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
|
||||||
|
|||||||
@@ -81,6 +81,7 @@
|
|||||||
#include "llappearancemgr.h"
|
#include "llappearancemgr.h"
|
||||||
|
|
||||||
#include "statemachine/aifilepicker.h"
|
#include "statemachine/aifilepicker.h"
|
||||||
|
#include "llxmltree.h"
|
||||||
|
|
||||||
using namespace LLAvatarAppearanceDefines;
|
using namespace LLAvatarAppearanceDefines;
|
||||||
|
|
||||||
@@ -297,7 +298,7 @@ void LLFloaterCustomize::onBtnImport()
|
|||||||
{
|
{
|
||||||
AIFilePicker* filepicker = AIFilePicker::create();
|
AIFilePicker* filepicker = AIFilePicker::create();
|
||||||
filepicker->open(FFLOAD_XML);
|
filepicker->open(FFLOAD_XML);
|
||||||
filepicker->run(boost::bind(&LLFloaterCustomize::onBtnImport_continued, filepicker));
|
filepicker->run(boost::bind(&LLFloaterCustomize::onBtnImport_continued, this, filepicker));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker)
|
void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker)
|
||||||
@@ -308,59 +309,123 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string filename = filepicker->getFilename();
|
// Find the editted wearable.
|
||||||
|
LLPanelEditWearable* panel_edit_wearable = getCurrentWearablePanel();
|
||||||
|
LLViewerWearable* edit_wearable = panel_edit_wearable->getWearable();
|
||||||
|
|
||||||
FILE* fp = LLFile::fopen(filename, "rb");
|
std::string const filename = filepicker->getFilename();
|
||||||
|
|
||||||
//char text_buffer[2048]; /* Flawfinder: ignore */
|
LLXmlTree xml;
|
||||||
S32 c;
|
BOOL success = xml.parseFile(filename, FALSE);
|
||||||
S32 typ;
|
if (!success)
|
||||||
S32 count;
|
|
||||||
S32 param_id=0;
|
|
||||||
F32 param_weight=0;
|
|
||||||
S32 fields_read;
|
|
||||||
|
|
||||||
for( S32 i=0; i < LLWearableType::WT_COUNT; i++ )
|
|
||||||
{
|
{
|
||||||
fields_read = fscanf( fp, "type %d\n", &typ);
|
llwarns << "Could not read or parse wearable import file \"" << filename << "\"." << llendl;
|
||||||
if( fields_read != 1 )
|
return;
|
||||||
|
}
|
||||||
|
LLXmlTreeNode* root = xml.getRoot();
|
||||||
|
if (!root)
|
||||||
{
|
{
|
||||||
llwarns << "Bad asset type: early end of file" << llendl;
|
llwarns << "No root node found in wearable import file: " << filename << llendl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fields_read = fscanf( fp, "parameters %d\n", &count);
|
//-------------------------------------------------------------------------
|
||||||
if( fields_read != 1 )
|
// <linden_genepool version="1.0"> (root)
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
if (!root->hasName("linden_genepool"))
|
||||||
{
|
{
|
||||||
llwarns << "Bad parameters : early end of file" << llendl;
|
llwarns << "Invalid wearable import file (missing linden_genepool header): " << filename << llendl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(c=0;c<count;c++)
|
static LLStdStringHandle const version_string = LLXmlTree::addAttributeString("version");
|
||||||
|
std::string version;
|
||||||
|
if (!root->getFastAttributeString(version_string, version) || (version != "1.0"))
|
||||||
{
|
{
|
||||||
fields_read = fscanf( fp, "%d %f\n", ¶m_id, ¶m_weight );
|
llwarns << "Invalid linden_genepool version: " << version << " in file: " << filename << llendl;
|
||||||
if( fields_read != 2 )
|
|
||||||
{
|
|
||||||
llwarns << "Bad parameters list: early end of file" << llendl;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LLWearable* wearable = gAgentWearables.getTopWearable((LLWearableType::EType)typ);
|
|
||||||
wearable->setVisualParamWeight(param_id, param_weight, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
//-------------------------------------------------------------------------
|
||||||
|
// <archetype name="???">
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
LLXmlTreeNode* archetype_node = root->getChildByName("archetype");
|
||||||
|
if (!archetype_node)
|
||||||
|
{
|
||||||
|
llwarns << "No archetype in wearable import file: " << filename << llendl;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the XML content.
|
||||||
|
static LLStdStringHandle const id_string = LLXmlTree::addAttributeString("id");
|
||||||
|
static LLStdStringHandle const value_string = LLXmlTree::addAttributeString("value");
|
||||||
|
for(LLXmlTreeNode* child = archetype_node->getFirstChild(); child; child = archetype_node->getNextChild())
|
||||||
|
{
|
||||||
|
if (!child->hasName("param"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string id_s;
|
||||||
|
U32 id;
|
||||||
|
std::string value_s;
|
||||||
|
F32 value;
|
||||||
|
if (!child->getFastAttributeString(id_string, id_s) || !LLStringUtil::convertToU32(id_s, id) ||
|
||||||
|
!child->getFastAttributeString(value_string, value_s) || !LLStringUtil::convertToF32(value_s, value))
|
||||||
|
{
|
||||||
|
llwarns << "Possible syntax error or corruption for <param id=... value=... /> node in " << filename << llendl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LLVisualParam* visual_param = edit_wearable->getVisualParam(id);
|
||||||
|
if (visual_param)
|
||||||
|
{
|
||||||
|
visual_param->setWeight(value, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edit_wearable->writeToAvatar(gAgentAvatarp);
|
||||||
|
gAgentAvatarp->updateVisualParams();
|
||||||
|
panel_edit_wearable->updateScrollingPanelUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
// reX: new function
|
// reX: new function
|
||||||
void LLFloaterCustomize::onBtnExport()
|
void LLFloaterCustomize::onBtnExport()
|
||||||
{
|
{
|
||||||
|
// Find the editted wearable.
|
||||||
|
LLPanelEditWearable* panel_edit_wearable = getCurrentWearablePanel();
|
||||||
|
LLViewerWearable* edit_wearable = panel_edit_wearable->getWearable();
|
||||||
|
U32 edit_index = panel_edit_wearable->getIndex();
|
||||||
|
std::string const& name = edit_wearable->getName();
|
||||||
|
|
||||||
|
// Determine if the currently selected wearable is modifiable.
|
||||||
|
LLWearableType::EType edit_type = getCurrentWearableType();
|
||||||
|
bool is_modifiable = false;
|
||||||
|
LLViewerWearable* old_wearable = gAgentWearables.getViewerWearable(edit_type, edit_index);
|
||||||
|
if (old_wearable)
|
||||||
|
{
|
||||||
|
LLViewerInventoryItem* item = gInventory.getItem(old_wearable->getItemID());
|
||||||
|
if (item)
|
||||||
|
{
|
||||||
|
LLPermissions const& perm = item->getPermissions();
|
||||||
|
// Modifiable means the user can see the sliders and type them over into a file anyway.
|
||||||
|
is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_modifiable)
|
||||||
|
{
|
||||||
|
// We should never get here, because in that case the Export button is disabled.
|
||||||
|
llwarns << "Cannot export current wearable \"" << name << "\" of type " << (int)edit_type << "because user lacks modify permissions." << llendl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string file_name = edit_wearable->getName() + "_" + edit_wearable->getTypeName() + "?000.xml";
|
||||||
|
std::string default_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
|
||||||
|
|
||||||
AIFilePicker* filepicker = AIFilePicker::create();
|
AIFilePicker* filepicker = AIFilePicker::create();
|
||||||
filepicker->open("", FFSAVE_XML);
|
filepicker->open(file_name, FFSAVE_XML, default_path, "archetype");
|
||||||
filepicker->run(boost::bind(&LLFloaterCustomize::onBtnExport_continued, filepicker));
|
filepicker->run(boost::bind(&LLFloaterCustomize::onBtnExport_continued, edit_wearable, filepicker));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker)
|
//static
|
||||||
|
void LLFloaterCustomize::onBtnExport_continued(LLViewerWearable* edit_wearable, AIFilePicker* filepicker)
|
||||||
{
|
{
|
||||||
if (!filepicker->hasFilename())
|
if (!filepicker->hasFilename())
|
||||||
{
|
{
|
||||||
@@ -368,62 +433,17 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLViewerInventoryItem* item;
|
LLAPRFile outfile;
|
||||||
BOOL is_modifiable;
|
outfile.open(filepicker->getFilename(), LL_APR_WB);
|
||||||
|
if (!outfile.getFileHandle())
|
||||||
const std::string filename = filepicker->getFilename();
|
|
||||||
|
|
||||||
FILE* fp = LLFile::fopen(filename, "wb");
|
|
||||||
|
|
||||||
for( S32 i=0; i < LLWearableType::WT_COUNT; i++ )
|
|
||||||
{
|
{
|
||||||
is_modifiable = FALSE;
|
llwarns << "Could not open \"" << filepicker->getFilename() << "\" for writing." << llendl;
|
||||||
LLViewerWearable* old_wearable = gAgentWearables.getViewerWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE
|
return;
|
||||||
if( old_wearable )
|
|
||||||
{
|
|
||||||
item = gInventory.getItem(old_wearable->getItemID());
|
|
||||||
if(item)
|
|
||||||
{
|
|
||||||
const LLPermissions& perm = item->getPermissions();
|
|
||||||
is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_modifiable)
|
|
||||||
{
|
|
||||||
old_wearable->FileExportParams(fp);
|
|
||||||
}
|
|
||||||
if (!is_modifiable)
|
|
||||||
{
|
|
||||||
fprintf( fp, "type %d\n",i);
|
|
||||||
fprintf( fp, "parameters 0\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for( S32 i=0; i < LLWearableType::WT_COUNT; i++ )
|
LLVOAvatar::dumpArchetypeXML_header(outfile);
|
||||||
{
|
edit_wearable->archetypeExport(outfile);
|
||||||
is_modifiable = FALSE;
|
LLVOAvatar::dumpArchetypeXML_footer(outfile);
|
||||||
LLViewerWearable* old_wearable = gAgentWearables.getViewerWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE
|
|
||||||
if( old_wearable )
|
|
||||||
{
|
|
||||||
item = gInventory.getItem(old_wearable->getItemID());
|
|
||||||
if(item)
|
|
||||||
{
|
|
||||||
const LLPermissions& perm = item->getPermissions();
|
|
||||||
is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is_modifiable)
|
|
||||||
{
|
|
||||||
old_wearable->FileExportTextures(fp);
|
|
||||||
}
|
|
||||||
if (!is_modifiable)
|
|
||||||
{
|
|
||||||
fprintf( fp, "type %d\n",i);
|
|
||||||
fprintf( fp, "textures 0\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFloaterCustomize::onBtnOk()
|
void LLFloaterCustomize::onBtnOk()
|
||||||
|
|||||||
@@ -125,9 +125,9 @@ private:
|
|||||||
void onBtnOk();
|
void onBtnOk();
|
||||||
void onBtnMakeOutfit();
|
void onBtnMakeOutfit();
|
||||||
void onBtnImport();
|
void onBtnImport();
|
||||||
static void onBtnImport_continued(AIFilePicker* filepicker);
|
void onBtnImport_continued(AIFilePicker* filepicker);
|
||||||
void onBtnExport();
|
void onBtnExport();
|
||||||
static void onBtnExport_continued(AIFilePicker* filepicker);
|
static void onBtnExport_continued(LLViewerWearable* edit_wearable, AIFilePicker* filepicker);
|
||||||
void onTabChanged( const LLSD& param );
|
void onTabChanged( const LLSD& param );
|
||||||
bool onTabPrecommit( LLUICtrl* ctrl, const LLSD& param );
|
bool onTabPrecommit( LLUICtrl* ctrl, const LLSD& param );
|
||||||
bool onSaveDialog(const LLSD& notification, const LLSD& response);
|
bool onSaveDialog(const LLSD& notification, const LLSD& response);
|
||||||
|
|||||||
@@ -953,22 +953,8 @@ void LLPanelEditWearable::setWearableIndex(S32 index)
|
|||||||
if(mActiveModal)
|
if(mActiveModal)
|
||||||
mActiveModal->close();
|
mActiveModal->close();
|
||||||
|
|
||||||
U32 perm_mask = wearable ? PERM_NONE : PERM_ALL;
|
bool editable = updatePermissions();
|
||||||
BOOL is_complete = wearable ? FALSE : TRUE;
|
|
||||||
if(wearable)
|
|
||||||
{
|
|
||||||
LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(wearable->getItemID());
|
|
||||||
if(item)
|
|
||||||
{
|
|
||||||
perm_mask = item->getPermissions().getMaskOwner();
|
|
||||||
is_complete = item->isComplete();
|
|
||||||
if(!is_complete)
|
|
||||||
{
|
|
||||||
item->fetchFromServer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setUIPermissions(perm_mask, is_complete);
|
|
||||||
if (mType == LLWearableType::WT_ALPHA)
|
if (mType == LLWearableType::WT_ALPHA)
|
||||||
{
|
{
|
||||||
initPreviousAlphaTextures();
|
initPreviousAlphaTextures();
|
||||||
@@ -980,7 +966,7 @@ void LLPanelEditWearable::setWearableIndex(S32 index)
|
|||||||
if(subpart_entry)
|
if(subpart_entry)
|
||||||
{
|
{
|
||||||
value_map_t sorted_params;
|
value_map_t sorted_params;
|
||||||
getSortedParams(sorted_params, subpart_entry->mEditGroup, ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE);
|
getSortedParams(sorted_params, subpart_entry->mEditGroup, editable);
|
||||||
buildParamList(mCustomizeFloater->getScrollingPanelList(), sorted_params);
|
buildParamList(mCustomizeFloater->getScrollingPanelList(), sorted_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1144,6 +1130,10 @@ LLViewerWearable* LLPanelEditWearable::getWearable() const
|
|||||||
return mCurrentWearable;//gAgentWearables.getWearable(mType, mCurrentIndex); // TODO: MULTI-WEARABLE
|
return mCurrentWearable;//gAgentWearables.getWearable(mType, mCurrentIndex); // TODO: MULTI-WEARABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 LLPanelEditWearable::getIndex() const
|
||||||
|
{
|
||||||
|
return mCurrentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
|
void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
|
||||||
{
|
{
|
||||||
@@ -1386,39 +1376,11 @@ void LLPanelEditWearable::changeCamera(U8 subpart)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the thumbnails we display
|
// Update the thumbnails we display
|
||||||
LLViewerWearable* wearable = getWearable();
|
bool editable = updatePermissions();
|
||||||
LLViewerInventoryItem* item = wearable ? gInventory.getItem(wearable->getItemID()) : NULL;
|
|
||||||
U32 perm_mask = 0x0;
|
|
||||||
BOOL is_complete = FALSE;
|
|
||||||
bool can_export = false;
|
|
||||||
bool can_import = false;
|
|
||||||
if(item)
|
|
||||||
{
|
|
||||||
perm_mask = item->getPermissions().getMaskOwner();
|
|
||||||
is_complete = item->isComplete();
|
|
||||||
|
|
||||||
if (subpart_e < SUBPART_EYES) // body parts only
|
|
||||||
{
|
|
||||||
can_import = true;
|
|
||||||
|
|
||||||
if (is_complete &&
|
|
||||||
gAgent.getID() == item->getPermissions().getOwner() &&
|
|
||||||
gAgent.getID() == item->getPermissions().getCreator() &&
|
|
||||||
(PERM_ITEM_UNRESTRICTED &
|
|
||||||
perm_mask) == PERM_ITEM_UNRESTRICTED)
|
|
||||||
{
|
|
||||||
can_export = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setUIPermissions(perm_mask, is_complete);
|
|
||||||
|
|
||||||
value_map_t sorted_params;
|
value_map_t sorted_params;
|
||||||
getSortedParams(sorted_params, subpart_entry->mEditGroup, ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE);
|
getSortedParams(sorted_params, subpart_entry->mEditGroup, editable);
|
||||||
buildParamList(mCustomizeFloater->getScrollingPanelList(), sorted_params);
|
buildParamList(mCustomizeFloater->getScrollingPanelList(), sorted_params);
|
||||||
updateScrollingPanelUI();
|
updateScrollingPanelUI();
|
||||||
mCustomizeFloater->childSetEnabled("Export", can_export);
|
|
||||||
mCustomizeFloater->childSetEnabled("Import", can_import);
|
|
||||||
|
|
||||||
// Update the camera
|
// Update the camera
|
||||||
if(gMorphView)
|
if(gMorphView)
|
||||||
@@ -1434,6 +1396,43 @@ void LLPanelEditWearable::changeCamera(U8 subpart)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Singu note: this function was split off from LLPanelEditWearable::changeCamera
|
||||||
|
// Return true if the current wearable is editable and update state accordingly.
|
||||||
|
bool LLPanelEditWearable::updatePermissions()
|
||||||
|
{
|
||||||
|
LLViewerWearable* wearable = getWearable();
|
||||||
|
LLViewerInventoryItem* item = wearable ? gInventory.getItem(wearable->getItemID()) : NULL;
|
||||||
|
U32 perm_mask = wearable ? PERM_NONE : PERM_ALL;
|
||||||
|
BOOL is_complete = wearable ? FALSE : TRUE;
|
||||||
|
bool can_export = false;
|
||||||
|
bool can_import = false;
|
||||||
|
if (item)
|
||||||
|
{
|
||||||
|
perm_mask = item->getPermissions().getMaskOwner();
|
||||||
|
is_complete = item->isComplete();
|
||||||
|
|
||||||
|
//Singu note: allow to import values over any modifiable wearable (why not?).
|
||||||
|
{
|
||||||
|
can_import = true;
|
||||||
|
|
||||||
|
// Exporting (of slider values) is allowed when the wearable is full perm, and owned by and created by the user.
|
||||||
|
// Of course, only modifiable is enough for the user to write down the values and enter them else where... but why make it easy for them to break the ToS.
|
||||||
|
if (is_complete &&
|
||||||
|
gAgent.getID() == item->getPermissions().getOwner() &&
|
||||||
|
gAgent.getID() == item->getPermissions().getCreator() &&
|
||||||
|
(PERM_ITEM_UNRESTRICTED &
|
||||||
|
perm_mask) == PERM_ITEM_UNRESTRICTED)
|
||||||
|
{
|
||||||
|
can_export = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setUIPermissions(perm_mask, is_complete);
|
||||||
|
mCustomizeFloater->childSetEnabled("Export", can_export);
|
||||||
|
mCustomizeFloater->childSetEnabled("Import", can_import);
|
||||||
|
return (perm_mask & PERM_MODIFY) && is_complete;
|
||||||
|
}
|
||||||
|
|
||||||
void LLPanelEditWearable::updateScrollingPanelList()
|
void LLPanelEditWearable::updateScrollingPanelList()
|
||||||
{
|
{
|
||||||
updateScrollingPanelUI();
|
updateScrollingPanelUI();
|
||||||
|
|||||||
@@ -62,10 +62,12 @@ public:
|
|||||||
|
|
||||||
// changes camera angle to default for selected subpart
|
// changes camera angle to default for selected subpart
|
||||||
void changeCamera(U8 subpart);
|
void changeCamera(U8 subpart);
|
||||||
|
bool updatePermissions();
|
||||||
|
|
||||||
const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); }
|
const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); }
|
||||||
LLWearableType::EType getType() const{ return mType; }
|
LLWearableType::EType getType() const{ return mType; }
|
||||||
LLViewerWearable* getWearable() const;
|
LLViewerWearable* getWearable() const;
|
||||||
|
U32 getIndex() const;
|
||||||
|
|
||||||
void onTabChanged(LLUICtrl* ctrl);
|
void onTabChanged(LLUICtrl* ctrl);
|
||||||
bool onTabPrecommit();
|
bool onTabPrecommit();
|
||||||
|
|||||||
@@ -4376,7 +4376,7 @@ void handle_dump_archetype_xml(void *)
|
|||||||
avatar = gAgentAvatarp;
|
avatar = gAgentAvatarp;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string file_name = avatar->getFullname() + (avatar->isSelf() ? "_s" : "_o") + ".xml";
|
std::string file_name = avatar->getFullname() + (avatar->isSelf() ? "_s" : "_o") + "?000.xml";
|
||||||
std::string default_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
|
std::string default_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
|
||||||
|
|
||||||
AIFilePicker* filepicker = AIFilePicker::create();
|
AIFilePicker* filepicker = AIFilePicker::create();
|
||||||
|
|||||||
@@ -7618,34 +7618,33 @@ bool LLVOAvatar::visualParamWeightsAreDefault()
|
|||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)
|
void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value)
|
||||||
{
|
{
|
||||||
std::string type_string = "unknown";
|
std::string type_string = "unknown";
|
||||||
if (dynamic_cast<LLTexLayerParamAlpha*>(viewer_param))
|
if (dynamic_cast<LLTexLayerParamAlpha const*>(viewer_param))
|
||||||
type_string = "param_alpha";
|
type_string = "param_alpha";
|
||||||
if (dynamic_cast<LLTexLayerParamColor*>(viewer_param))
|
if (dynamic_cast<LLTexLayerParamColor const*>(viewer_param))
|
||||||
type_string = "param_color";
|
type_string = "param_color";
|
||||||
if (dynamic_cast<LLDriverParam*>(viewer_param))
|
if (dynamic_cast<LLDriverParam const*>(viewer_param))
|
||||||
type_string = "param_driver";
|
type_string = "param_driver";
|
||||||
if (dynamic_cast<LLPolyMorphTarget*>(viewer_param))
|
if (dynamic_cast<LLPolyMorphTarget const*>(viewer_param))
|
||||||
type_string = "param_morph";
|
type_string = "param_morph";
|
||||||
if (dynamic_cast<LLPolySkeletalDistortion*>(viewer_param))
|
if (dynamic_cast<LLPolySkeletalDistortion const*>(viewer_param))
|
||||||
type_string = "param_skeleton";
|
type_string = "param_skeleton";
|
||||||
S32 wtype = -1;
|
S32 wtype = -1;
|
||||||
LLViewerVisualParam *vparam = dynamic_cast<LLViewerVisualParam*>(viewer_param);
|
LLViewerVisualParam const* vparam = dynamic_cast<LLViewerVisualParam const*>(viewer_param);
|
||||||
if (vparam)
|
if (vparam)
|
||||||
{
|
{
|
||||||
wtype = vparam->getWearableType();
|
wtype = vparam->getWearableType();
|
||||||
}
|
}
|
||||||
S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight());
|
S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight());
|
||||||
apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\"/>\n",
|
apr_file_printf(file.getFileHandle(), "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\"/>\n",
|
||||||
viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(),
|
viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(),
|
||||||
LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str()
|
LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str()
|
||||||
// param_location_name(vparam->getParamLocation()).c_str()
|
// param_location_name(vparam->getParamLocation()).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
|
void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
|
||||||
const std::vector<F32>& params_for_dump,
|
const std::vector<F32>& params_for_dump,
|
||||||
const LLTEContents& tec)
|
const LLTEContents& tec)
|
||||||
@@ -7675,7 +7674,7 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
|
|||||||
}
|
}
|
||||||
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
|
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
|
||||||
F32 value = params_for_dump[i];
|
F32 value = params_for_dump[i];
|
||||||
dump_visual_param(file, viewer_param, value);
|
dump_visual_param(outfile, viewer_param, value);
|
||||||
param = getNextVisualParam();
|
param = getNextVisualParam();
|
||||||
}
|
}
|
||||||
for (U32 i = 0; i < tec.face_count; i++)
|
for (U32 i = 0; i < tec.face_count; i++)
|
||||||
@@ -8301,7 +8300,24 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
|
|||||||
dumpArchetypeXML_cont(fullpath, group_by_wearables);
|
dumpArchetypeXML_cont(fullpath, group_by_wearables);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables )
|
//static
|
||||||
|
void LLVOAvatar::dumpArchetypeXML_header(LLAPRFile& file)
|
||||||
|
{
|
||||||
|
apr_file_t* fp = file.getFileHandle();
|
||||||
|
apr_file_printf(fp, "<?xml version=\"1.0\" encoding=\"US-ASCII\" standalone=\"yes\"?>\n");
|
||||||
|
apr_file_printf(fp, "<linden_genepool version=\"1.0\">\n");
|
||||||
|
apr_file_printf(fp, "\n\t<archetype name=\"???\">\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
void LLVOAvatar::dumpArchetypeXML_footer(LLAPRFile& file)
|
||||||
|
{
|
||||||
|
apr_file_t* fp = file.getFileHandle();
|
||||||
|
apr_file_printf(fp, "\t</archetype>\n");
|
||||||
|
apr_file_printf(fp, "\n</linden_genepool>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables)
|
||||||
{
|
{
|
||||||
LLAPRFile outfile;
|
LLAPRFile outfile;
|
||||||
outfile.open(fullpath, LL_APR_WB );
|
outfile.open(fullpath, LL_APR_WB );
|
||||||
@@ -8315,9 +8331,7 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b
|
|||||||
llinfos << "xmlfile write handle obtained : " << fullpath << llendl;
|
llinfos << "xmlfile write handle obtained : " << fullpath << llendl;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_file_printf( file, "<?xml version=\"1.0\" encoding=\"US-ASCII\" standalone=\"yes\"?>\n" );
|
LLVOAvatar::dumpArchetypeXML_header(outfile);
|
||||||
apr_file_printf( file, "<linden_genepool version=\"1.0\">\n" );
|
|
||||||
apr_file_printf( file, "\n\t<archetype name=\"???\">\n" );
|
|
||||||
|
|
||||||
if (group_by_wearables)
|
if (group_by_wearables)
|
||||||
{
|
{
|
||||||
@@ -8332,7 +8346,7 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b
|
|||||||
if( (viewer_param->getWearableType() == type) &&
|
if( (viewer_param->getWearableType() == type) &&
|
||||||
(viewer_param->isTweakable() ) )
|
(viewer_param->isTweakable() ) )
|
||||||
{
|
{
|
||||||
dump_visual_param(file, viewer_param, viewer_param->getWeight());
|
dump_visual_param(outfile, viewer_param, viewer_param->getWeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8358,7 +8372,7 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b
|
|||||||
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
|
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
|
||||||
{
|
{
|
||||||
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
|
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
|
||||||
dump_visual_param(file, viewer_param, viewer_param->getWeight());
|
dump_visual_param(outfile, viewer_param, viewer_param->getWeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
|
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
|
||||||
@@ -8376,8 +8390,8 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
apr_file_printf( file, "\t</archetype>\n" );
|
|
||||||
apr_file_printf( file, "\n</linden_genepool>\n" );
|
LLVOAvatar::dumpArchetypeXML_footer(outfile);
|
||||||
|
|
||||||
bool ultra_verbose = false;
|
bool ultra_verbose = false;
|
||||||
if (isSelf() && ultra_verbose)
|
if (isSelf() && ultra_verbose)
|
||||||
@@ -8388,7 +8402,6 @@ void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_b
|
|||||||
// File will close when handle goes out of scope
|
// File will close when handle goes out of scope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LLVOAvatar::setVisibilityRank(U32 rank)
|
void LLVOAvatar::setVisibilityRank(U32 rank)
|
||||||
{
|
{
|
||||||
if (mDrawable.isNull() || mDrawable->isDead())
|
if (mDrawable.isNull() || mDrawable->isDead())
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ extern const LLUUID ANIM_AGENT_PELVIS_FIX;
|
|||||||
extern const LLUUID ANIM_AGENT_TARGET;
|
extern const LLUUID ANIM_AGENT_TARGET;
|
||||||
extern const LLUUID ANIM_AGENT_WALK_ADJUST;
|
extern const LLUUID ANIM_AGENT_WALK_ADJUST;
|
||||||
|
|
||||||
|
class LLAPRFile;
|
||||||
class LLViewerWearable;
|
class LLViewerWearable;
|
||||||
class LLVoiceVisualizer;
|
class LLVoiceVisualizer;
|
||||||
class LLHUDNameTag;
|
class LLHUDNameTag;
|
||||||
@@ -986,6 +987,8 @@ private:
|
|||||||
// General
|
// General
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
public:
|
public:
|
||||||
|
static void dumpArchetypeXML_header(LLAPRFile& file);
|
||||||
|
static void dumpArchetypeXML_footer(LLAPRFile& file);
|
||||||
void dumpArchetypeXML(const std::string& prefix, bool group_by_wearables = false);
|
void dumpArchetypeXML(const std::string& prefix, bool group_by_wearables = false);
|
||||||
void dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables);
|
void dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables);
|
||||||
void dumpAppearanceMsgParams( const std::string& dump_prefix,
|
void dumpAppearanceMsgParams( const std::string& dump_prefix,
|
||||||
|
|||||||
@@ -3195,7 +3195,7 @@ void LLVOAvatarSelf::dumpScratchTextureByteCount()
|
|||||||
llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl;
|
llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value);
|
void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value);
|
||||||
|
|
||||||
void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
|
void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
|
||||||
{
|
{
|
||||||
@@ -3223,7 +3223,7 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
|
|||||||
it != v_params.end(); ++it)
|
it != v_params.end(); ++it)
|
||||||
{
|
{
|
||||||
LLVisualParam *param = *it;
|
LLVisualParam *param = *it;
|
||||||
dump_visual_param(file, param, param->getWeight());
|
dump_visual_param(outfile, param, param->getWeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1435,10 +1435,12 @@ one from scratch and wear it.
|
|||||||
</text>
|
</text>
|
||||||
<button name="Import" label="Import"
|
<button name="Import" label="Import"
|
||||||
bottom="-486" left="10" height="20" width="70"
|
bottom="-486" left="10" height="20" width="70"
|
||||||
follows="left|bottom" font="SansSerif" halign="center" />
|
follows="left|bottom" font="SansSerif" halign="center"
|
||||||
|
tool_tip="Import to currently selected wearable; current wearable must be modifiable" />
|
||||||
<button name="Export" label="Export"
|
<button name="Export" label="Export"
|
||||||
bottom="-506" left="10" height="20" width="70"
|
bottom="-506" left="10" height="20" width="70"
|
||||||
follows="left|bottom" font="SansSerif" halign="center" />
|
follows="left|bottom" font="SansSerif" halign="center"
|
||||||
|
tool_tip="Export currently selected wearable; asset must be copy/mod/trans and you need to be the creator" />
|
||||||
<button bottom="-536" follows="right|bottom" font="SansSerif" halign="center"
|
<button bottom="-536" follows="right|bottom" font="SansSerif" halign="center"
|
||||||
height="20" label="Cancel" label_selected="Cancel" mouse_opaque="true"
|
height="20" label="Cancel" label_selected="Cancel" mouse_opaque="true"
|
||||||
name="Cancel" right="-10" scale_image="true" width="100" />
|
name="Cancel" right="-10" scale_image="true" width="100" />
|
||||||
|
|||||||
Reference in New Issue
Block a user