Skip to content

Properly warn when scaling textures down instead of being entirely silent. #4404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions indra/llprimitive/llmodelloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ LLModelLoader::LLModelLoader(
, mLod(lod)
, mTrySLM(false)
, mFirstTransform(true)
, mNumOfFetchingTextures(0)
, mLoadCallback(load_cb)
, mJointLookupFunc(joint_lookup_func)
, mTextureLoadFunc(texture_load_func)
Expand All @@ -134,6 +133,7 @@ LLModelLoader::LLModelLoader(
, mNoNormalize(false)
, mNoOptimize(false)
, mCacheOnlyHitIfRigged(false)
, mTexturesNeedScaling(false)
, mMaxJointsPerMesh(maxJointsPerMesh)
, mGeneratedModelLimit(modelLimit)
, mDebugMode(debugMode)
Expand Down Expand Up @@ -669,7 +669,7 @@ void LLModelLoader::loadTextures()

if(!material.mDiffuseMapFilename.empty())
{
mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData);
mTextureLoadFunc(material, mOpaqueData);
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions indra/llprimitive/llmodelloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class LLModelLoader : public LLThread

bool mTrySLM;
bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info)
bool mTexturesNeedScaling;

model_list mModelList;
// The scene is pretty much what ends up getting loaded for upload. Basically assign things to this guy if you want something uploaded.
Expand Down Expand Up @@ -170,9 +171,6 @@ class LLModelLoader : public LLThread

void stretch_extents(const LLModel* model, const LLMatrix4& mat);

S32 mNumOfFetchingTextures ; // updated in the main thread
bool areTexturesReady() { return !mNumOfFetchingTextures; } // called in the main thread.

bool verifyCount( int expected, int result );

//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
Expand Down
1 change: 1 addition & 0 deletions indra/newview/gltf/llgltfloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ LLGLTFLoader::LLGLTFImportMaterial LLGLTFLoader::processMaterial(S32 material_in
LL::GLTF::Image& image = mGLTFAsset.mImages[sourceIndex];
if (image.mTexture.notNull())
{
mTexturesNeedScaling |= image.mHeight > LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT || image.mWidth > LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT;
impMat.setDiffuseMap(image.mTexture->getID());
LL_INFOS("GLTF_IMPORT") << "Using existing texture ID: " << image.mTexture->getID().asString() << LL_ENDL;
}
Expand Down
8 changes: 4 additions & 4 deletions indra/newview/llfloatermodelpreview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,26 +1340,26 @@ void LLFloaterModelPreview::addStringToLog(const std::string& message, const LLS
{
std::string str;
switch (lod)
{
{
case LLModel::LOD_IMPOSTOR: str = "LOD0 "; break;
case LLModel::LOD_LOW: str = "LOD1 "; break;
case LLModel::LOD_MEDIUM: str = "LOD2 "; break;
case LLModel::LOD_PHYSICS: str = "PHYS "; break;
case LLModel::LOD_HIGH: str = "LOD3 "; break;
default: break;
}
}

LLStringUtil::format_map_t args_msg;
LLSD::map_const_iterator iter = args.beginMap();
LLSD::map_const_iterator end = args.endMap();
for (; iter != end; ++iter)
{
{
args_msg[iter->first] = iter->second.asString();
}
str += sInstance->getString(message, args_msg);
sInstance->addStringToLogTab(str, flash);
}
}
}

// static
void LLFloaterModelPreview::addStringToLog(const std::string& str, bool flash)
Expand Down
36 changes: 36 additions & 0 deletions indra/newview/llmaterialeditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2479,6 +2479,42 @@ void LLMaterialEditor::loadMaterial(const tinygltf::Model &model_in, const std::
pack_textures(base_color_img, normal_img, mr_img, emissive_img, occlusion_img,
mBaseColorJ2C, mNormalJ2C, mMetallicRoughnessJ2C, mEmissiveJ2C);

if (open_floater)
{
bool textures_scaled = false;
if (mBaseColorFetched && mBaseColorJ2C
&& (mBaseColorFetched->getWidth() != mBaseColorJ2C->getWidth()
|| mBaseColorFetched->getHeight() != mBaseColorJ2C->getHeight()))
{
textures_scaled = true;
}
else if (mNormalFetched && mNormalJ2C
&& (mNormalFetched->getWidth() != mNormalJ2C->getWidth()
|| mNormalFetched->getHeight() != mNormalJ2C->getHeight()))
{
textures_scaled = true;
}
else if (mMetallicRoughnessFetched && mMetallicRoughnessJ2C
&& (mMetallicRoughnessFetched->getWidth() != mMetallicRoughnessJ2C->getWidth()
|| mMetallicRoughnessFetched->getHeight() != mMetallicRoughnessJ2C->getHeight()))
{
textures_scaled = true;
}
else if (mEmissiveFetched && mEmissiveJ2C
&& (mEmissiveFetched->getWidth() != mEmissiveJ2C->getWidth()
|| mEmissiveFetched->getHeight() != mEmissiveJ2C->getHeight()))
{
textures_scaled = true;
}

if (textures_scaled)
{
LLSD args;
args["MAX_SIZE"] = LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT;
LLNotificationsUtil::add("MaterialImagesWereScaled", args);
}
}

LLUUID base_color_id;
if (mBaseColorFetched.notNull())
{
Expand Down
38 changes: 30 additions & 8 deletions indra/newview/llmodelpreview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
, mLastJointUpdate(false)
, mFirstSkinUpdate(true)
, mHasDegenerate(false)
, mNumOfFetchingTextures(0)
, mTexturesNeedScaling(false)
, mImporterDebug(LLCachedControl<bool>(gSavedSettings, "ImporterDebugVerboseLogging", false))
{
mNeedsUpdate = true;
Expand Down Expand Up @@ -559,10 +561,7 @@ void LLModelPreview::rebuildUploadData()
texture->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, true, false, new LLHandle<LLModelPreview>(getHandle()), &mCallbackTextureList, false);
texture->forceToSaveRawImage(0, F32_MAX);
texture->updateFetch();
if (mModelLoader)
{
mModelLoader->mNumOfFetchingTextures++;
}
mNumOfFetchingTextures++;
}
}
}
Expand Down Expand Up @@ -997,7 +996,9 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload());
setLegacyRigFlags(mModelLoader->getLegacyRigFlags());

mTexturesNeedScaling |= mModelLoader->mTexturesNeedScaling;
mModelLoader->loadTextures();
warnTextureScaling();

if (loaded_lod == -1)
{ //populate all LoDs from model loader scene
Expand Down Expand Up @@ -2510,7 +2511,7 @@ void LLModelPreview::updateStatusMessages()
LLMutexLock lock(this);
if (mModelLoader)
{
if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean())
if (!areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean())
{
// Some textures are still loading, prevent upload until they are done
mModelNoErrors = false;
Expand Down Expand Up @@ -3216,6 +3217,7 @@ U32 LLModelPreview::loadTextures(LLImportMaterial& material, LLHandle<LLModelPre
tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, true, false, new LLHandle<LLModelPreview>(handle), &preview->mCallbackTextureList, false);
tex->forceToSaveRawImage(0, F32_MAX);
material.setDiffuseMap(tex->getID()); // record tex ID
preview->mNumOfFetchingTextures++;
return 1;
}

Expand Down Expand Up @@ -4060,6 +4062,18 @@ void LLModelPreview::setPreviewLOD(S32 lod)
updateStatusMessages();
}

void LLModelPreview::warnTextureScaling()
{
if (areTexturesReady() && mTexturesNeedScaling)
{
std::ostringstream out;
out << "One or more textures in this model were scaled to be within the allowed limits.";
LL_INFOS() << out.str() << LL_ENDL;
LLSD args;
LLFloaterModelPreview::addStringToLog("ModelTextureScaling", args, true, -1);
}
}

//static
void LLModelPreview::textureLoadedCallback(
bool success,
Expand All @@ -4080,11 +4094,19 @@ void LLModelPreview::textureLoadedCallback(
LLModelPreview* preview = static_cast<LLModelPreview*>(handle->get());
preview->refresh();

if (final && preview->mModelLoader)
if (final)
{
if (preview->mModelLoader->mNumOfFetchingTextures > 0)
if (src_vi
&& (src_vi->getOriginalWidth() > LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT
|| src_vi->getOriginalHeight() > LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT))
{
preview->mTexturesNeedScaling = true;
}

if (preview->mNumOfFetchingTextures > 0)
{
preview->mModelLoader->mNumOfFetchingTextures--;
preview->mNumOfFetchingTextures--;
preview->warnTextureScaling();
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions indra/newview/llmodelpreview.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex, public LLH
std::vector<S32> mLodsQuery;
std::vector<S32> mLodsWithParsingError;
bool mHasDegenerate;
bool areTexturesReady() { return !mNumOfFetchingTextures; }

protected:

Expand All @@ -213,6 +214,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex, public LLH
static LLJoint* lookupJointByName(const std::string&, void* opaque);
static U32 loadTextures(LLImportMaterial& material, LLHandle<LLModelPreview> handle);

void warnTextureScaling();
void lookupLODModelFiles(S32 lod);

private:
Expand Down Expand Up @@ -242,6 +244,9 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex, public LLH
/// Not read unless mWarnOfUnmatchedPhyicsMeshes is true.
LLPointer<LLModel> mDefaultPhysicsShapeP;

S32 mNumOfFetchingTextures;
bool mTexturesNeedScaling;

typedef enum
{
MESH_OPTIMIZER_FULL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<string name="decomposing">Analyzing...</string>
<string name="simplifying">Simplifying...</string>
<string name="tbd">TBD</string>
<string name="ModelTextureScaling">One or more textures in this model were scaled to be within the allowed limits.</string>

<!-- Warnings and info from model loader-->
<string name="TooManyJoint">Skinning disabled due to too many joints: [JOINTS], maximum: [MAX]</string>
Expand Down
14 changes: 14 additions & 0 deletions indra/newview/skins/default/xui/en/notifications.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7135,6 +7135,20 @@ You don&apos;t have permission to view this notecard.
<tag>fail</tag>
</notification>

<notification
icon="alertmodal.tga"
name="MaterialImagesWereScaled"
type="alertmodal">
One or more textures in this material were scaled to be within the allowed limits.
Textures must have power of two dimensions and must not exceed [MAX_SIZE]x[MAX_SIZE] pixels.
<unique/>
<tag>confirm</tag>
<usetemplate
ignoretext="Warn if textures will be scaled during upload."
name="okignore"
yestext="OK"/>
</notification>

<notification
icon="notifytip.tga"
name="RezItemNoPermissions"
Expand Down
Loading