#4515 Improve ordering of sub-meshes upon upload

master
Andrey Kleshchev 2025-09-24 21:02:57 +03:00
parent 97ff76c420
commit 351b7763a8
4 changed files with 266 additions and 315 deletions

View File

@ -2570,7 +2570,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_
return MESH_OK;
}
LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, const LLMeshUploadThread::lod_sources_map_t& sources_list,
LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list_t& data, const LLMeshUploadThread::lod_sources_map_t& sources_list,
LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
const std::string & upload_url, LLUUID destination_folder_id, bool do_upload,
@ -2652,7 +2652,7 @@ void LLMeshUploadThread::DecompRequest::completed()
void LLMeshUploadThread::preStart()
{
//build map of LLModel refs to instances for callbacks
for (instance_list::iterator iter = mInstanceList.begin(); iter != mInstanceList.end(); ++iter)
for (instance_list_t::iterator iter = mInstanceList.begin(); iter != mInstanceList.end(); ++iter)
{
mInstance[iter->mModel].push_back(*iter);
}
@ -2701,6 +2701,179 @@ LLSD llsd_from_file(std::string filename)
return result;
}
void LLMeshUploadThread::packModelIntance(
LLModel* model,
LLMeshUploadThread::instance_list_t& instance_list,
std::string& model_name,
LLSD& res,
S32& mesh_num,
S32& texture_num,
S32& instance_num,
std::unordered_set<LLViewerTexture* >& textures,
std::unordered_map<LLViewerTexture*, S32> texture_index,
std::unordered_map<LLModel*, S32>& mesh_index,
std::vector<std::string>& texture_list_dest,
bool include_textures
)
{
LLMeshUploadData data;
data.mBaseModel = model;
LLModelInstance& first_instance = *(instance_list.begin());
for (S32 i = 0; i < 5; i++)
{
data.mModel[i] = first_instance.mLOD[i];
}
if (mesh_index.find(data.mBaseModel) == mesh_index.end())
{
// Have not seen this model before - create a new mesh_list entry for it.
if (model_name.empty())
{
model_name = data.mBaseModel->getName();
}
std::stringstream ostr;
LLModel::Decomposition& decomp =
data.mModel[LLModel::LOD_PHYSICS].notNull() ?
data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
data.mBaseModel->mPhysics;
decomp.mBaseHull = mHullMap[data.mBaseModel];
LLSD mesh_header = LLModel::writeModel(
ostr,
data.mModel[LLModel::LOD_PHYSICS],
data.mModel[LLModel::LOD_HIGH],
data.mModel[LLModel::LOD_MEDIUM],
data.mModel[LLModel::LOD_LOW],
data.mModel[LLModel::LOD_IMPOSTOR],
decomp,
mUploadSkin,
mUploadJoints,
mLockScaleIfJointPosition,
LLModel::WRITE_BINARY,
false,
data.mBaseModel->mSubmodelID);
data.mAssetData = ostr.str();
std::string str = ostr.str();
res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(), str.end());
mesh_index[data.mBaseModel] = mesh_num;
mesh_num++;
}
// For all instances that use this model
for (instance_list_t::iterator instance_iter = instance_list.begin();
instance_iter != instance_list.end();
++instance_iter)
{
LLModelInstance& instance = *instance_iter;
LLSD instance_entry;
for (S32 i = 0; i < 5; i++)
{
data.mModel[i] = instance.mLOD[i];
}
LLVector3 pos, scale;
LLQuaternion rot;
LLMatrix4 transformation = instance.mTransform;
decomposeMeshMatrix(transformation, pos, rot, scale);
instance_entry["position"] = ll_sd_from_vector3(pos);
instance_entry["rotation"] = ll_sd_from_quaternion(rot);
instance_entry["scale"] = ll_sd_from_vector3(scale);
instance_entry["material"] = LL_MCODE_WOOD;
if (model->mSubmodelID)
{
// Should it really be different?
instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_NONE);
}
else
{
instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
}
instance_entry["mesh"] = mesh_index[data.mBaseModel];
instance_entry["mesh_name"] = instance.mLabel;
instance_entry["face_list"] = LLSD::emptyArray();
// We want to be able to allow more than 8 materials...
//
S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), instance.mModel->getNumVolumeFaces());
for (S32 face_num = 0; face_num < end; face_num++)
{
// multiple faces can reuse the same material
LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
LLSD face_entry = LLSD::emptyMap();
LLViewerFetchedTexture* texture = NULL;
if (material.mDiffuseMapFilename.size())
{
texture = FindViewerTexture(material);
}
if ((texture != NULL) &&
(textures.find(texture) == textures.end()))
{
textures.insert(texture);
}
std::stringstream texture_str;
if (texture != NULL && include_textures && mUploadTextures)
{
if (texture->hasSavedRawImage())
{
LLImageDataLock lock(texture->getSavedRawImage());
LLPointer<LLImageJ2C> upload_file =
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
if (!upload_file.isNull() && upload_file->getDataSize() && !upload_file->isBufferInvalid())
{
texture_str.write((const char*)upload_file->getData(), upload_file->getDataSize());
}
}
}
if (texture != NULL &&
mUploadTextures &&
texture_index.find(texture) == texture_index.end())
{
texture_index[texture] = texture_num;
std::string str = texture_str.str();
res["texture_list"][texture_num] = LLSD::Binary(str.begin(), str.end());
// store indexes for error handling;
texture_list_dest.push_back(material.mDiffuseMapFilename);
texture_num++;
}
// Subset of TextureEntry fields.
if (texture != NULL && mUploadTextures)
{
face_entry["image"] = texture_index[texture];
face_entry["scales"] = 1.0;
face_entry["scalet"] = 1.0;
face_entry["offsets"] = 0.0;
face_entry["offsett"] = 0.0;
face_entry["imagerot"] = 0.0;
}
face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor);
face_entry["fullbright"] = material.mFullbright;
instance_entry["face_list"][face_num] = face_entry;
}
res["instance_list"][instance_num] = instance_entry;
instance_num++;
}
}
void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector<std::string>& texture_list_dest, bool include_textures)
{
LLSD result;
@ -2734,6 +2907,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector<std::string>&
}
S32 mesh_num = 0;
S32 texture_num = 0;
S32 instance_num = 0;
std::unordered_set<LLViewerTexture* > textures;
std::unordered_map<LLViewerTexture*,S32> texture_index;
@ -2741,7 +2915,34 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector<std::string>&
std::unordered_map<LLModel*,S32> mesh_index;
std::string model_name;
S32 instance_num = 0;
// If server gets a m1, m2, m3, m4 list, m1 becomes the root
// and the rest go as m4, m3, m2
// to counter that mInstance is sorted as m4, m3, m2, m1
// and we grab m1 from the end and send it first
LLModel* root_model = nullptr;
for (instance_map_t::reverse_iterator iter = mInstance.rbegin(); iter != mInstance.rend(); ++iter)
{
if (iter->first->mSubmodelID)
{
// Submodel can't be root
continue;
}
root_model = iter->first;
packModelIntance(
iter->first,
iter->second,
model_name,
res,
mesh_num,
texture_num,
instance_num,
textures,
texture_index,
mesh_index,
texture_list_dest,
include_textures);
break;
}
// Handle models, ignore submodels for now.
// Probably should pre-sort by mSubmodelID instead of running twice.
@ -2749,319 +2950,53 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector<std::string>&
// deterministic order.
for (auto& iter : mInstance)
{
LLMeshUploadData data;
data.mBaseModel = iter.first;
if (data.mBaseModel->mSubmodelID)
if (iter.first->mSubmodelID)
{
// These are handled below to insure correct parenting order on creation
// due to map walking being based on model address (aka random)
continue;
}
LLModelInstance& first_instance = *(iter.second.begin());
for (S32 i = 0; i < 5; i++)
if (root_model == iter.first)
{
data.mModel[i] = first_instance.mLOD[i];
}
if (mesh_index.find(data.mBaseModel) == mesh_index.end())
{
// Have not seen this model before - create a new mesh_list entry for it.
if (model_name.empty())
{
model_name = data.mBaseModel->getName();
}
std::stringstream ostr;
LLModel::Decomposition& decomp =
data.mModel[LLModel::LOD_PHYSICS].notNull() ?
data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
data.mBaseModel->mPhysics;
decomp.mBaseHull = mHullMap[data.mBaseModel];
LLSD mesh_header = LLModel::writeModel(
ostr,
data.mModel[LLModel::LOD_PHYSICS],
data.mModel[LLModel::LOD_HIGH],
data.mModel[LLModel::LOD_MEDIUM],
data.mModel[LLModel::LOD_LOW],
data.mModel[LLModel::LOD_IMPOSTOR],
decomp,
mUploadSkin,
mUploadJoints,
mLockScaleIfJointPosition,
LLModel::WRITE_BINARY,
false,
data.mBaseModel->mSubmodelID);
data.mAssetData = ostr.str();
std::string str = ostr.str();
res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end());
mesh_index[data.mBaseModel] = mesh_num;
mesh_num++;
}
// For all instances that use this model
for (instance_list::iterator instance_iter = iter.second.begin();
instance_iter != iter.second.end();
++instance_iter)
{
LLModelInstance& instance = *instance_iter;
LLSD instance_entry;
for (S32 i = 0; i < 5; i++)
{
data.mModel[i] = instance.mLOD[i];
}
LLVector3 pos, scale;
LLQuaternion rot;
LLMatrix4 transformation = instance.mTransform;
decomposeMeshMatrix(transformation,pos,rot,scale);
instance_entry["position"] = ll_sd_from_vector3(pos);
instance_entry["rotation"] = ll_sd_from_quaternion(rot);
instance_entry["scale"] = ll_sd_from_vector3(scale);
instance_entry["material"] = LL_MCODE_WOOD;
instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
instance_entry["mesh"] = mesh_index[data.mBaseModel];
instance_entry["mesh_name"] = instance.mLabel;
instance_entry["face_list"] = LLSD::emptyArray();
// We want to be able to allow more than 8 materials...
//
S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), instance.mModel->getNumVolumeFaces()) ;
for (S32 face_num = 0; face_num < end; face_num++)
{
// multiple faces can reuse the same material
LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
LLSD face_entry = LLSD::emptyMap();
LLViewerFetchedTexture *texture = NULL;
if (material.mDiffuseMapFilename.size())
{
texture = FindViewerTexture(material);
}
if ((texture != NULL) &&
(textures.find(texture) == textures.end()))
{
textures.insert(texture);
}
std::stringstream texture_str;
if (texture != NULL && include_textures && mUploadTextures)
{
if (texture->hasSavedRawImage())
{
LLImageDataLock lock(texture->getSavedRawImage());
LLPointer<LLImageJ2C> upload_file =
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
if (!upload_file.isNull() && upload_file->getDataSize() && !upload_file->isBufferInvalid())
{
texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
}
}
}
if (texture != NULL &&
mUploadTextures &&
texture_index.find(texture) == texture_index.end())
{
texture_index[texture] = texture_num;
std::string str = texture_str.str();
res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
// store indexes for error handling;
texture_list_dest.push_back(material.mDiffuseMapFilename);
texture_num++;
}
// Subset of TextureEntry fields.
if (texture != NULL && mUploadTextures)
{
face_entry["image"] = texture_index[texture];
face_entry["scales"] = 1.0;
face_entry["scalet"] = 1.0;
face_entry["offsets"] = 0.0;
face_entry["offsett"] = 0.0;
face_entry["imagerot"] = 0.0;
}
face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor);
face_entry["fullbright"] = material.mFullbright;
instance_entry["face_list"][face_num] = face_entry;
}
res["instance_list"][instance_num] = instance_entry;
instance_num++;
// Reached root, root was already packed and is last non-submodel
break;
}
packModelIntance(
iter.first,
iter.second,
model_name,
res,
mesh_num,
texture_num,
instance_num,
textures,
texture_index,
mesh_index,
texture_list_dest,
include_textures);
}
// Now handle the submodels.
for (auto& iter : mInstance)
{
LLMeshUploadData data;
data.mBaseModel = iter.first;
if (!data.mBaseModel->mSubmodelID)
if (!iter.first->mSubmodelID)
{
// These were handled above already...
//
continue;
}
LLModelInstance& first_instance = *(iter.second.begin());
for (S32 i = 0; i < 5; i++)
{
data.mModel[i] = first_instance.mLOD[i];
}
if (mesh_index.find(data.mBaseModel) == mesh_index.end())
{
// Have not seen this model before - create a new mesh_list entry for it.
if (model_name.empty())
{
model_name = data.mBaseModel->getName();
}
std::stringstream ostr;
LLModel::Decomposition& decomp =
data.mModel[LLModel::LOD_PHYSICS].notNull() ?
data.mModel[LLModel::LOD_PHYSICS]->mPhysics :
data.mBaseModel->mPhysics;
decomp.mBaseHull = mHullMap[data.mBaseModel];
LLSD mesh_header = LLModel::writeModel(
ostr,
data.mModel[LLModel::LOD_PHYSICS],
data.mModel[LLModel::LOD_HIGH],
data.mModel[LLModel::LOD_MEDIUM],
data.mModel[LLModel::LOD_LOW],
data.mModel[LLModel::LOD_IMPOSTOR],
decomp,
mUploadSkin,
mUploadJoints,
mLockScaleIfJointPosition,
LLModel::WRITE_BINARY,
false,
data.mBaseModel->mSubmodelID);
data.mAssetData = ostr.str();
std::string str = ostr.str();
res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end());
mesh_index[data.mBaseModel] = mesh_num;
mesh_num++;
}
// For all instances that use this model
for (instance_list::iterator instance_iter = iter.second.begin();
instance_iter != iter.second.end();
++instance_iter)
{
LLModelInstance& instance = *instance_iter;
LLSD instance_entry;
for (S32 i = 0; i < 5; i++)
{
data.mModel[i] = instance.mLOD[i];
}
LLVector3 pos, scale;
LLQuaternion rot;
LLMatrix4 transformation = instance.mTransform;
decomposeMeshMatrix(transformation,pos,rot,scale);
instance_entry["position"] = ll_sd_from_vector3(pos);
instance_entry["rotation"] = ll_sd_from_quaternion(rot);
instance_entry["scale"] = ll_sd_from_vector3(scale);
instance_entry["material"] = LL_MCODE_WOOD;
instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_NONE);
instance_entry["mesh"] = mesh_index[data.mBaseModel];
instance_entry["face_list"] = LLSD::emptyArray();
// We want to be able to allow more than 8 materials...
//
S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ;
for (S32 face_num = 0; face_num < end; face_num++)
{
LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
LLSD face_entry = LLSD::emptyMap();
LLViewerFetchedTexture *texture = NULL;
if (material.mDiffuseMapFilename.size())
{
texture = FindViewerTexture(material);
}
if ((texture != NULL) &&
(textures.find(texture) == textures.end()))
{
textures.insert(texture);
}
std::stringstream texture_str;
if (texture != NULL && include_textures && mUploadTextures)
{
if (texture->hasSavedRawImage())
{
LLImageDataLock lock(texture->getSavedRawImage());
LLPointer<LLImageJ2C> upload_file =
LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
if (!upload_file.isNull() && upload_file->getDataSize())
{
texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
}
}
}
if (texture != NULL &&
mUploadTextures &&
texture_index.find(texture) == texture_index.end())
{
texture_index[texture] = texture_num;
std::string str = texture_str.str();
res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
texture_num++;
}
// Subset of TextureEntry fields.
if (texture != NULL && mUploadTextures)
{
face_entry["image"] = texture_index[texture];
face_entry["scales"] = 1.0;
face_entry["scalet"] = 1.0;
face_entry["offsets"] = 0.0;
face_entry["offsett"] = 0.0;
face_entry["imagerot"] = 0.0;
}
face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor);
face_entry["fullbright"] = material.mFullbright;
instance_entry["face_list"][face_num] = face_entry;
}
res["instance_list"][instance_num] = instance_entry;
instance_num++;
}
packModelIntance(
iter.first,
iter.second,
model_name,
res,
mesh_num,
texture_num,
instance_num,
textures,
texture_index,
mesh_index,
texture_list_dest,
include_textures);
}
if (model_name.empty()) model_name = "mesh model";
@ -3077,7 +3012,7 @@ void LLMeshUploadThread::generateHulls()
{
bool has_valid_requests = false ;
for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
for (instance_map_t::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
{
LLMeshUploadData data;
data.mBaseModel = iter->first;

View File

@ -668,11 +668,11 @@ public:
LLPointer<DecompRequest> mFinalDecomp;
volatile bool mPhysicsComplete;
typedef std::map<LLPointer<LLModel>, std::vector<LLVector3> > hull_map;
hull_map mHullMap;
typedef std::map<LLPointer<LLModel>, std::vector<LLVector3> > hull_map_t;
hull_map_t mHullMap;
typedef std::vector<LLModelInstance> instance_list;
instance_list mInstanceList;
typedef std::vector<LLModelInstance> instance_list_t;
instance_list_t mInstanceList;
// Upload should happen in deterministic order, so sort instances by model name.
struct LLUploadModelInstanceLess
@ -686,11 +686,11 @@ public:
}
// Note: probably can sort by mBaseModel->mSubmodelID here as well to avoid
// running over the list twice in wholeModelToLLSD.
return a->mLabel < b->mLabel;
return a->mLabel > b->mLabel;
}
};
typedef std::map<LLPointer<LLModel>, instance_list, LLUploadModelInstanceLess> instance_map;
instance_map mInstance;
typedef std::map<LLPointer<LLModel>, instance_list_t, LLUploadModelInstanceLess> instance_map_t;
instance_map_t mInstance;
typedef std::map<std::string, std::string> lod_sources_map_t;
lod_sources_map_t mLodSources;
@ -709,7 +709,7 @@ public:
std::string mWholeModelUploadURL;
LLUUID mDestinationFolderId;
LLMeshUploadThread(instance_list& data, const lod_sources_map_t& sources_list,
LLMeshUploadThread(instance_list_t& data, const lod_sources_map_t& sources_list,
LLVector3& scale, bool upload_textures,
bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,
const std::string & upload_url,
@ -745,6 +745,22 @@ public:
static LLViewerFetchedTexture* FindViewerTexture(const LLImportMaterial& material);
protected:
void packModelIntance(
LLModel* model,
LLMeshUploadThread::instance_list_t& instance_list,
std::string& model_name,
LLSD& res,
S32& mesh_num,
S32& texture_num,
S32& instance_num,
std::unordered_set<LLViewerTexture* > &textures,
std::unordered_map<LLViewerTexture*, S32> texture_index,
std::unordered_map<LLModel*, S32>& mesh_index,
std::vector<std::string>& texture_list_dest,
bool include_textures
);
private:
LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;
LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle;

View File

@ -576,7 +576,7 @@ void LLModelPreview::rebuildUploadData()
for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind)
{
bool found_model = false;
for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
for (LLMeshUploadThread::instance_list_t::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
LLModelInstance& instance = *iter;
if (instance.mLOD[lod] == mModel[lod][model_ind])
@ -2209,7 +2209,7 @@ void LLModelPreview::updateStatusMessages()
total_submeshes[i] = 0;
}
for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
for (LLMeshUploadThread::instance_list_t::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
LLModelInstance& instance = *iter;
@ -3530,7 +3530,7 @@ bool LLModelPreview::render()
if (!show_skin_weight)
{
for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
for (LLMeshUploadThread::instance_list_t::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
LLModelInstance& instance = *iter;
@ -3616,7 +3616,7 @@ bool LLModelPreview::render()
gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
for (LLMeshUploadThread::instance_list_t::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
LLModelInstance& instance = *iter;
@ -3738,7 +3738,7 @@ bool LLModelPreview::render()
gGL.diffuseColor4f(1.f, 0.f, 0.f, 1.f);
const LLVector4a scale(0.5f);
for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
for (LLMeshUploadThread::instance_list_t::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
LLModelInstance& instance = *iter;

View File

@ -319,7 +319,7 @@ protected:
// Amount of triangles in original(base) model
U32 mMaxTriangleLimit;
LLMeshUploadThread::instance_list mUploadData;
LLMeshUploadThread::instance_list_t mUploadData;
std::set<LLViewerFetchedTexture * > mTextureSet;
LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList;