diff options
| author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-08-19 01:45:47 +0300 | 
|---|---|---|
| committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-08-23 00:22:10 +0300 | 
| commit | 4bb419031c130402a5589ff698e28e230a0c123a (patch) | |
| tree | aee7a287a57cea846a228fbe75c9f62bbc001340 | |
| parent | 15cd6c1cb757060754680bec6101df7c0675cb38 (diff) | |
SL-17653 Basic local gltf materials
| -rw-r--r-- | indra/newview/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | indra/newview/llgltfmateriallist.cpp | 87 | ||||
| -rw-r--r-- | indra/newview/llgltfmateriallist.h | 3 | ||||
| -rw-r--r-- | indra/newview/lllocalrendermaterials.cpp | 734 | ||||
| -rw-r--r-- | indra/newview/lllocalrendermaterials.h | 136 | ||||
| -rw-r--r-- | indra/newview/llmaterialeditor.cpp | 103 | ||||
| -rw-r--r-- | indra/newview/lltinygltfhelper.cpp | 245 | ||||
| -rw-r--r-- | indra/newview/lltinygltfhelper.h | 55 | ||||
| -rw-r--r-- | indra/newview/llviewertexturelist.h | 6 | 
9 files changed, 1204 insertions, 169 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b67bc91277..e72536e781 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -394,6 +394,7 @@ set(viewer_SOURCE_FILES      lllistcontextmenu.cpp      lllistview.cpp      lllocalbitmaps.cpp +	lllocalrendermaterials.cpp      lllocationhistory.cpp      lllocationinputctrl.cpp      lllogchat.cpp @@ -607,6 +608,7 @@ set(viewer_SOURCE_FILES      lltextureinfodetails.cpp      lltexturestats.cpp      lltextureview.cpp +	lltinygltfhelper.cpp      lltoast.cpp      lltoastalertpanel.cpp      lltoastgroupnotifypanel.cpp @@ -1036,6 +1038,7 @@ set(viewer_HEADER_FILES      lllistcontextmenu.h      lllistview.h      lllocalbitmaps.h +	lllocalrendermaterials.h      lllocationhistory.h      lllocationinputctrl.h      lllogchat.h @@ -1240,6 +1243,7 @@ set(viewer_HEADER_FILES      lltextureinfodetails.h      lltexturestats.h      lltextureview.h +	lltinygltfhelper.h      lltoast.h      lltoastalertpanel.h      lltoastgroupnotifypanel.h diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index 96c29d7ed2..af00cdd05f 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -30,86 +30,13 @@  #include "llassetstorage.h"  #include "llfilesystem.h"  #include "llsdserialize.h" +#include "lltinygltfhelper.h"  #include "tinygltf/tiny_gltf.h"  #include <strstream>  LLGLTFMaterialList gGLTFMaterialList; -static LLColor4 get_color(const std::vector<double>& in) -{ -    LLColor4 out; -    for (S32 i = 0; i < llmin((S32)in.size(), 4); ++i) -    { -        out.mV[i] = in[i]; -    } - -    return out; -} - -static void set_from_model(LLGLTFMaterial* mat, tinygltf::Model& model) -{ -     -    S32 index; -     -    auto& material_in = model.materials[0]; - -    // get albedo texture -    index = material_in.pbrMetallicRoughness.baseColorTexture.index; -    if (index >= 0) -    { -        mat->mAlbedoId.set(model.images[index].uri); -    } -    else -    { -        mat->mAlbedoId.setNull(); -    } - -    // get normal map -    index = material_in.normalTexture.index; -    if (index >= 0) -    { -        mat->mNormalId.set(model.images[index].uri); -    } -    else -    { -        mat->mNormalId.setNull(); -    } - -    // get metallic-roughness texture -    index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index; -    if (index >= 0) -    { -        mat->mMetallicRoughnessId.set(model.images[index].uri); -    } -    else -    { -        mat->mMetallicRoughnessId.setNull(); -    } - -    // get emissive texture -    index = material_in.emissiveTexture.index; -    if (index >= 0) -    { -        mat->mEmissiveId.set(model.images[index].uri); -    } -    else -    { -        mat->mEmissiveId.setNull(); -    } - -    mat->setAlphaMode(material_in.alphaMode); -    mat->mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f); - -    mat->mAlbedoColor = get_color(material_in.pbrMetallicRoughness.baseColorFactor); -    mat->mEmissiveColor = get_color(material_in.emissiveFactor); - -    mat->mMetallicFactor = llclamp((F32)material_in.pbrMetallicRoughness.metallicFactor, 0.f, 1.f); -    mat->mRoughnessFactor = llclamp((F32)material_in.pbrMetallicRoughness.roughnessFactor, 0.f, 1.f); - -    mat->mDoubleSided = material_in.doubleSided; -} -  LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)  {      List::iterator iter = mList.find(id); @@ -158,7 +85,7 @@ LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)                                  if (loader.LoadASCIIFromString(&model_in, &error_msg, &warn_msg, data.c_str(), data.length(), ""))                                  { -                                    set_from_model(mat, model_in); +                                    LLTinyGLTFHelper::setFromModel(mat, model_in);                                  }                                  else                                  { @@ -184,3 +111,13 @@ LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)      return iter->second;  } +void LLGLTFMaterialList::addMaterial(const LLUUID& id, LLGLTFMaterial* material) +{ +    mList[id] = material; +} + +void LLGLTFMaterialList::removeMaterial(const LLUUID& id) +{ +    mList.erase(id); +} + diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h index c22134c468..49760504e6 100644 --- a/indra/newview/llgltfmateriallist.h +++ b/indra/newview/llgltfmateriallist.h @@ -41,6 +41,9 @@ public:      LLGLTFMaterial* getMaterial(const LLUUID& id); +    void addMaterial(const LLUUID& id, LLGLTFMaterial* material); +    void removeMaterial(const LLUUID& id); +  };  extern LLGLTFMaterialList gGLTFMaterialList; diff --git a/indra/newview/lllocalrendermaterials.cpp b/indra/newview/lllocalrendermaterials.cpp new file mode 100644 index 0000000000..aada61a056 --- /dev/null +++ b/indra/newview/lllocalrendermaterials.cpp @@ -0,0 +1,734 @@ +/**  + * @file lllocalrendermaterials.cpp + * @brief Local GLTF materials source + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +/* precompiled headers */ +#include "llviewerprecompiledheaders.h" + +/* own header */ +#include "lllocalrendermaterials.h" + +/* boost: will not compile unless equivalent is undef'd, beware. */ +#include "fix_macros.h" +#include <boost/filesystem.hpp> + +/* time headers */ +#include <time.h> +#include <ctime> + +/* misc headers */ +#include "llagentwearables.h" +#include "llface.h" +#include "llfilepicker.h" +#include "llgltfmateriallist.h" +#include "llimagedimensionsinfo.h" +#include "lllocaltextureobject.h" +#include "llmaterialmgr.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "lltexlayerparams.h" +#include "lltinygltfhelper.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewerdisplay.h" +#include "llviewerobjectlist.h" +#include "llviewerobject.h" +#include "llviewerwearable.h" +#include "llvoavatarself.h" +#include "llvovolume.h" +#include "pipeline.h" +#include "tinygltf/tiny_gltf.h" + +/*=======================================*/ +/*  Formal declarations, constants, etc. */ +/*=======================================*/  + +static const F32 LL_LOCAL_TIMER_HEARTBEAT   = 3.0; +static const BOOL LL_LOCAL_USE_MIPMAPS      = true; +static const S32 LL_LOCAL_DISCARD_LEVEL     = 0; +static const bool LL_LOCAL_SLAM_FOR_DEBUG   = true; +static const bool LL_LOCAL_REPLACE_ON_DEL   = true; +static const S32 LL_LOCAL_UPDATE_RETRIES    = 5; + +/*=======================================*/ +/*  LLLocalGLTFMaterial: unit class            */ +/*=======================================*/  +LLLocalGLTFMaterial::LLLocalGLTFMaterial(std::string filename) +	: mFilename(filename) +	, mShortName(gDirUtilp->getBaseFileName(filename, true)) +	, mValid(false) +	, mLastModified() +	, mLinkStatus(LS_ON) +	, mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) +{ +	mTrackingID.generate(); + +	/* extension */ +	std::string temp_exten = gDirUtilp->getExtension(mFilename); + +	if (temp_exten == "gltf") +	{  +		mExtension = ET_MATERIAL_GLTF; +	} +	else if (temp_exten == "glb") +	{ +		mExtension = ET_MATERIAL_GLB; +	} +	else +	{ +		LL_WARNS() << "File of no valid extension given, local material creation aborted." << "\n" +			    << "Filename: " << mFilename << LL_ENDL; +		return; // no valid extension. +	} + +	/* next phase of unit creation is nearly the same as an update cycle. +	   we're running updateSelf as a special case with the optional UT_FIRSTUSE +	   which omits the parts associated with removing the outdated texture */ +	mValid = updateSelf(UT_FIRSTUSE); +} + +LLLocalGLTFMaterial::~LLLocalGLTFMaterial() +{ +	// replace IDs with defaults, if set to do so. +	if(LL_LOCAL_REPLACE_ON_DEL && mValid && gAgentAvatarp) // fix for STORM-1837 +	{ +		replaceIDs(mWorldID, IMG_DEFAULT); +		LLLocalGLTFMaterialMgr::getInstance()->doRebake(); +	} + +	// delete self from material list +    gGLTFMaterialList.removeMaterial(mWorldID); +} + +/* accessors */ +std::string LLLocalGLTFMaterial::getFilename() +{ +	return mFilename; +} + +std::string LLLocalGLTFMaterial::getShortName() +{ +	return mShortName; +} + +LLUUID LLLocalGLTFMaterial::getTrackingID() +{ +	return mTrackingID; +} + +LLUUID LLLocalGLTFMaterial::getWorldID() +{ +	return mWorldID; +} + +bool LLLocalGLTFMaterial::getValid() +{ +	return mValid; +} + +/* update functions */ +bool LLLocalGLTFMaterial::updateSelf(EUpdateType optional_firstupdate) +{ +	bool updated = false; +	 +	if (mLinkStatus == LS_ON) +	{ +		// verifying that the file exists +		if (gDirUtilp->fileExists(mFilename)) +		{ +			// verifying that the file has indeed been modified + +#ifndef LL_WINDOWS +			const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); +#else +			const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename))); +#endif +			LLSD new_last_modified = asctime(localtime(&temp_time)); + +			if (mLastModified.asString() != new_last_modified.asString()) +			{ +				LLPointer<LLGLTFMaterial> raw_material = new LLGLTFMaterial(); +				if (loadMaterial(raw_material)) +				{ +					// decode is successful, we can safely proceed. +					LLUUID old_id = LLUUID::null; +					if ((optional_firstupdate != UT_FIRSTUSE) && !mWorldID.isNull()) +					{ +						old_id = mWorldID; +					} +					mWorldID.generate(); +					mLastModified = new_last_modified; + +                    gGLTFMaterialList.addMaterial(mWorldID, raw_material); +			 +					if (optional_firstupdate != UT_FIRSTUSE) +					{ +						// seek out everything old_id uses and replace it with mWorldID +						replaceIDs(old_id, mWorldID); + +						// remove old_id from material list +                        gGLTFMaterialList.removeMaterial(old_id); +					} + +					mUpdateRetries = LL_LOCAL_UPDATE_RETRIES; +					updated = true; +				} + +				// if decoding failed, we get here and it will attempt to decode it in the next cycles +				// until mUpdateRetries runs out. this is done because some software lock the material while writing to it +				else +				{ +					if (mUpdateRetries) +					{ +						mUpdateRetries--; +					} +					else +					{ +						LL_WARNS() << "During the update process the following file was found" << "\n" +							    << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n" +								<< "Filename: " << mFilename << "\n" +								<< "Disabling further update attempts for this file." << LL_ENDL; + +						LLSD notif_args; +						notif_args["FNAME"] = mFilename; +						notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES; +						LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args); + +						mLinkStatus = LS_BROKEN; +					} +				}		 +			} +			 +		} // end if file exists + +		else +		{ +			LL_WARNS() << "During the update process, the following file was not found." << "\n"  +			        << "Filename: " << mFilename << "\n" +				    << "Disabling further update attempts for this file." << LL_ENDL; + +			LLSD notif_args; +			notif_args["FNAME"] = mFilename; +			LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args); + +			mLinkStatus = LS_BROKEN; +		} +	} + +	return updated; +} + +bool LLLocalGLTFMaterial::loadMaterial(LLPointer<LLGLTFMaterial> mat) +{ +    bool decode_successful = false; + +    switch (mExtension) +    { +    case ET_MATERIAL_GLTF: +    case ET_MATERIAL_GLB: +    { +            tinygltf::TinyGLTF loader; +            std::string        error_msg; +            std::string        warn_msg; + +            tinygltf::Model model_in; + +            std::string filename_lc = mFilename; +            LLStringUtil::toLower(filename_lc); + +            // Load a tinygltf model fom a file. Assumes that the input filename has already been +            // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish. +            if (std::string::npos == filename_lc.rfind(".gltf")) +            {  // file is binary +                decode_successful = loader.LoadBinaryFromFile(&model_in, &error_msg, &warn_msg, filename_lc); +            } +            else +            {  // file is ascii +                decode_successful = loader.LoadASCIIFromFile(&model_in, &error_msg, &warn_msg, filename_lc); +            } + +            if (!decode_successful) +            { +                LL_WARNS() << "Cannot Upload Material, error: " << error_msg +                    << ", warning:" << warn_msg +                    << " file: " << mFilename +                    << LL_ENDL; +                break; +            } + +            if (model_in.materials.empty()) +            { +                // materials are missing +                LL_WARNS() << "Cannot Upload Material, Material missing, " << mFilename << LL_ENDL; +                decode_successful = false; +                break; +            } + +            // sets everything, but textures will have inaccurate ids +            LLTinyGLTFHelper::setFromModel(mat, model_in); + +            std::string folder = gDirUtilp->getDirName(filename_lc); +            tinygltf::Material material_in = model_in.materials[0]; + +            // get albedo texture +            LLPointer<LLImageRaw> albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index); +            // get normal map +            LLPointer<LLImageRaw> normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index); +            // get metallic-roughness texture +            LLPointer<LLImageRaw> mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index); +            // get emissive texture +            LLPointer<LLImageRaw> emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index); +            // get occlusion map if needed +            LLPointer<LLImageRaw> occlusion_img; +            if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index) +            { +                occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index); +            } + +            // todo: pass it into local bitmaps? +            LLTinyGLTFHelper::initFetchedTextures(material_in, +                albedo_img, normal_img, mr_img, emissive_img, occlusion_img, +                mAlbedoFetched, mNormalFetched, mMRFetched, mEmissiveFetched); + +            mat->mAlbedoId = mAlbedoFetched->getID(); +            mat->mNormalId = mNormalFetched->getID(); +            mat->mMetallicRoughnessId = mMRFetched->getID(); +            mat->mEmissiveId = mEmissiveFetched->getID(); + +            break; +        } + +        default: +        { +            // separating this into -several- LL_WARNS() calls because in the extremely unlikely case that this happens +            // accessing mFilename and any other object properties might very well crash the viewer. +            // getting here should be impossible, or there's been a pretty serious bug. + +            LL_WARNS() << "During a decode attempt, the following local material had no properly assigned extension." << LL_ENDL; +            LL_WARNS() << "Filename: " << mFilename << LL_ENDL; +            LL_WARNS() << "Disabling further update attempts for this file." << LL_ENDL; +            mLinkStatus = LS_BROKEN; +        } +    } + +    return decode_successful; +} + +void LLLocalGLTFMaterial::replaceIDs(LLUUID old_id, LLUUID new_id) +{ +    // checking for misuse. +    if (old_id == new_id) +    { +        LL_INFOS() << "An attempt was made to replace a texture with itself. (matching UUIDs)" << "\n" +            << "Texture UUID: " << old_id.asString() << LL_ENDL; +        return; +    } + +    // processing updates per channel; makes the process scalable. +    // the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc. +    updateUserPrims(old_id, new_id, LLRender::DIFFUSE_MAP); +    updateUserPrims(old_id, new_id, LLRender::NORMAL_MAP); +    updateUserPrims(old_id, new_id, LLRender::SPECULAR_MAP); + +    // default safeguard image for layers +    if (new_id == IMG_DEFAULT) +    { +        new_id = IMG_DEFAULT_AVATAR; +    } +} + +// this function sorts the faces from a getFaceList[getNumFaces] into a list of objects +// in order to prevent multiple sendTEUpdate calls per object during updateUserPrims +std::vector<LLViewerObject*> LLLocalGLTFMaterial::prepUpdateObjects(LLUUID old_id, U32 channel) +{ +    std::vector<LLViewerObject*> obj_list; +    // todo: find a way to update materials +    /* +    LLGLTFMaterial* old_material = gGLTFMaterialList.getMaterial(old_id); + +    for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++) +    { +        // getting an object from a face +        LLFace* face_to_object = (*old_texture->getFaceList(channel))[face_iterator]; + +        if(face_to_object) +        { +            LLViewerObject* affected_object = face_to_object->getViewerObject(); + +            if(affected_object) +            { + +                // we have an object, we'll take it's UUID and compare it to +                // whatever we already have in the returnable object list. +                // if there is a match - we do not add (to prevent duplicates) +                LLUUID mainlist_obj_id = affected_object->getID(); +                bool add_object = true; + +                // begin looking for duplicates +                std::vector<LLViewerObject*>::iterator objlist_iter = obj_list.begin(); +                for(; (objlist_iter != obj_list.end()) && add_object; objlist_iter++) +                { +                    LLViewerObject* obj = *objlist_iter; +                    if (obj->getID() == mainlist_obj_id) +                    { +                        add_object = false; // duplicate found. +                    } +                } +                // end looking for duplicates + +                if(add_object) +                { +                    obj_list.push_back(affected_object); +                } + +            } + +        } + +    } // end of face-iterating for() + +    */ +    return obj_list; +} + +void LLLocalGLTFMaterial::updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel) +{ +    /*std::vector<LLViewerObject*> objectlist = prepUpdateObjects(old_id, channel); +    for(std::vector<LLViewerObject*>::iterator object_iterator = objectlist.begin(); +        object_iterator != objectlist.end(); object_iterator++) +    { +        LLViewerObject* object = *object_iterator; + +        if(object) +        { +            bool update_tex = false; +            bool update_mat = false; +            S32 num_faces = object->getNumFaces(); + +            for (U8 face_iter = 0; face_iter < num_faces; face_iter++) +            { +                if (object->mDrawable) +                { +                    LLFace* face = object->mDrawable->getFace(face_iter); +                    if (face && face->getTexture(channel) && face->getTexture(channel)->getID() == old_id) +                    { +                        // these things differ per channel, unless there already is a universal +                        // texture setting function to setTE that takes channel as a param? +                        // p.s.: switch for now, might become if - if an extra test is needed to verify before touching normalmap/specmap +                        switch(channel) +                        { +                            case LLRender::DIFFUSE_MAP: +                    { +                                object->setTETexture(face_iter, new_id); +                                update_tex = true; +                                break; +                            } + +                            case LLRender::NORMAL_MAP: +                            { +                                object->setTENormalMap(face_iter, new_id); +                                update_mat = true; +                                update_tex = true; +                                break; +                            } + +                            case LLRender::SPECULAR_MAP: +                            { +                                object->setTESpecularMap(face_iter, new_id); +                                update_mat = true; +                                update_tex = true; +                                break; +                            } +                        } +                        // end switch + +                    } +                } +            } + +            if (update_tex) +            { +                object->sendTEUpdate(); +            } + +            if (update_mat) +            { +                object->mDrawable->getVOVolume()->faceMappingChanged(); +            } +        } +    } +    */ +} + +/*=======================================*/ +/*  LLLocalGLTFMaterialTimer: timer class      */ +/*=======================================*/ +LLLocalGLTFMaterialTimer::LLLocalGLTFMaterialTimer() : LLEventTimer(LL_LOCAL_TIMER_HEARTBEAT) +{ +} + +LLLocalGLTFMaterialTimer::~LLLocalGLTFMaterialTimer() +{ +} + +void LLLocalGLTFMaterialTimer::startTimer() +{ +    mEventTimer.start(); +} + +void LLLocalGLTFMaterialTimer::stopTimer() +{ +    mEventTimer.stop(); +} + +bool LLLocalGLTFMaterialTimer::isRunning() +{ +    return mEventTimer.getStarted(); +} + +BOOL LLLocalGLTFMaterialTimer::tick() +{ +    // todo: do on idle? No point in timer  +    LLLocalGLTFMaterialMgr::getInstance()->doUpdates(); +    return FALSE; +} + +/*=======================================*/ +/*  LLLocalGLTFMaterialMgr: manager class      */ +/*=======================================*/ +LLLocalGLTFMaterialMgr::LLLocalGLTFMaterialMgr() +{ +} + +LLLocalGLTFMaterialMgr::~LLLocalGLTFMaterialMgr() +{ +    std::for_each(mMaterialList.begin(), mMaterialList.end(), DeletePointer()); +    mMaterialList.clear(); +} + +bool LLLocalGLTFMaterialMgr::addUnit() +{ +    bool add_successful = false; + +    LLFilePicker& picker = LLFilePicker::instance(); +    if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) +    { +        mTimer.stopTimer(); + +        std::string filename = picker.getFirstFile(); +        while (!filename.empty()) +        { +            if (!checkTextureDimensions(filename)) +            { +                filename = picker.getNextFile(); +                continue; +            } + +            LLLocalGLTFMaterial* unit = new LLLocalGLTFMaterial(filename); + +            if (unit->getValid()) +            { +                mMaterialList.push_back(unit); +                add_successful = true; +            } +            else +            { +                LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n" +                    << "Filename: " << filename << LL_ENDL; + +                LLSD notif_args; +                notif_args["FNAME"] = filename; +                LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args); + +                delete unit; +                unit = NULL; +            } + +            filename = picker.getNextFile(); +        } + +        mTimer.startTimer(); +    } + +    return add_successful; +} + +bool LLLocalGLTFMaterialMgr::checkTextureDimensions(std::string filename) +{ +    std::string exten = gDirUtilp->getExtension(filename); +    U32 codec = LLImageBase::getCodecFromExtension(exten); +    std::string mImageLoadError; +    LLImageDimensionsInfo image_info; +    if (!image_info.load(filename, codec)) +    { +        return false; +    } + +    S32 max_width = gSavedSettings.getS32("max_texture_dimension_X"); +    S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y"); + +    if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height)) +    { +        LLStringUtil::format_map_t args; +        args["WIDTH"] = llformat("%d", max_width); +        args["HEIGHT"] = llformat("%d", max_height); +        mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args); + +        LLSD notif_args; +        notif_args["REASON"] = mImageLoadError; +        LLNotificationsUtil::add("CannotUploadTexture", notif_args); + +        return false; +    } + +    return true; +} + +void LLLocalGLTFMaterialMgr::delUnit(LLUUID tracking_id) +{ +    if (!mMaterialList.empty()) +    { +        std::vector<LLLocalGLTFMaterial*> to_delete; +        for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) +        {   /* finding which ones we want deleted and making a separate list */ +            LLLocalGLTFMaterial* unit = *iter; +            if (unit->getTrackingID() == tracking_id) +            { +                to_delete.push_back(unit); +            } +        } + +        for (std::vector<LLLocalGLTFMaterial*>::iterator del_iter = to_delete.begin(); +            del_iter != to_delete.end(); del_iter++) +        {   /* iterating over a temporary list, hence preserving the iterator validity while deleting. */ +            LLLocalGLTFMaterial* unit = *del_iter; +            mMaterialList.remove(unit); +            delete unit; +            unit = NULL; +        } +    } +} + +LLUUID LLLocalGLTFMaterialMgr::getWorldID(LLUUID tracking_id) +{ +    LLUUID world_id = LLUUID::null; + +    for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) +    { +        LLLocalGLTFMaterial* unit = *iter; +        if (unit->getTrackingID() == tracking_id) +        { +            world_id = unit->getWorldID(); +        } +    } + +    return world_id; +} + +bool LLLocalGLTFMaterialMgr::isLocal(const LLUUID world_id) +{ +    for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) +    { +        LLLocalGLTFMaterial* unit = *iter; +        if (unit->getWorldID() == world_id) +        { +            return true; +        } +    } +    return false; +} + +std::string LLLocalGLTFMaterialMgr::getFilename(LLUUID tracking_id) +{ +    std::string filename = ""; + +    for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) +    { +        LLLocalGLTFMaterial* unit = *iter; +        if (unit->getTrackingID() == tracking_id) +        { +            filename = unit->getFilename(); +        } +    } + +    return filename; +} + +void LLLocalGLTFMaterialMgr::feedScrollList(LLScrollListCtrl* ctrl) +{ +    if (ctrl) +    { +        ctrl->clearRows(); + +        if (!mMaterialList.empty()) +        { +            for (local_list_iter iter = mMaterialList.begin(); +                iter != mMaterialList.end(); iter++) +            { +                LLSD element; +                element["columns"][0]["column"] = "unit_name"; +                element["columns"][0]["type"] = "text"; +                element["columns"][0]["value"] = (*iter)->getShortName(); + +                element["columns"][1]["column"] = "unit_id_HIDDEN"; +                element["columns"][1]["type"] = "text"; +                element["columns"][1]["value"] = (*iter)->getTrackingID(); + +                ctrl->addElement(element); +            } +        } +    } + +} + +void LLLocalGLTFMaterialMgr::doUpdates() +{ +    // preventing theoretical overlap in cases with huge number of loaded images. +    mTimer.stopTimer(); +    mNeedsRebake = false; + +    for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) +    { +        (*iter)->updateSelf(); +    } + +    doRebake(); +    mTimer.startTimer(); +} + +void LLLocalGLTFMaterialMgr::setNeedsRebake() +{ +    mNeedsRebake = true; +} + +void LLLocalGLTFMaterialMgr::doRebake() +{ /* separated that from doUpdates to insure a rebake can be called separately during deletion */ +    if (mNeedsRebake) +    { +        gAgentAvatarp->forceBakeAllTextures(LL_LOCAL_SLAM_FOR_DEBUG); +        mNeedsRebake = false; +    } +} + diff --git a/indra/newview/lllocalrendermaterials.h b/indra/newview/lllocalrendermaterials.h new file mode 100644 index 0000000000..ea1edbb7b1 --- /dev/null +++ b/indra/newview/lllocalrendermaterials.h @@ -0,0 +1,136 @@ +/**  + * @file lllocalrendermaterials.h + * @brief Local GLTF materials header + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_LOCALRENDERMATERIALS_H +#define LL_LOCALRENDERMATERIALS_H + +#include "lleventtimer.h" +#include "llpointer.h" + +class LLScrollListCtrl; +class LLGLTFMaterial; +class LLViewerObject; +class LLViewerFetchedTexture; + +class LLLocalGLTFMaterial +{ +public: /* main */ +    LLLocalGLTFMaterial(std::string filename); +    ~LLLocalGLTFMaterial(); + +public: /* accessors */ +    std::string	getFilename(); +    std::string	getShortName(); +    LLUUID		getTrackingID(); +    LLUUID		getWorldID(); +    bool		getValid(); + +public: /* self update public section */ +    enum EUpdateType +    { +        UT_FIRSTUSE, +        UT_REGUPDATE +    }; + +    bool updateSelf(EUpdateType = UT_REGUPDATE); + +private: /* self update private section */ +    bool loadMaterial(LLPointer<LLGLTFMaterial> raw); +    void replaceIDs(LLUUID old_id, LLUUID new_id); +    std::vector<LLViewerObject*> prepUpdateObjects(LLUUID old_id, U32 channel); +    void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel); + +private: /* private enums */ +    enum ELinkStatus +    { +        LS_ON, +        LS_BROKEN, +    }; + +    enum EExtension +    { +        ET_MATERIAL_GLTF, +        ET_MATERIAL_GLB, +    }; + +private: /* members */ +    std::string mFilename; +    std::string mShortName; +    LLUUID      mTrackingID; +    LLUUID      mWorldID; +    bool        mValid; +    LLSD        mLastModified; +    EExtension  mExtension; +    ELinkStatus mLinkStatus; +    S32         mUpdateRetries; + +    // material needs to maintain textures +    LLPointer<LLViewerFetchedTexture> mAlbedoFetched; +    LLPointer<LLViewerFetchedTexture> mNormalFetched; +    LLPointer<LLViewerFetchedTexture> mMRFetched; +    LLPointer<LLViewerFetchedTexture> mEmissiveFetched; +}; + +class LLLocalGLTFMaterialTimer : public LLEventTimer +{ +public: +    LLLocalGLTFMaterialTimer(); +    ~LLLocalGLTFMaterialTimer(); + +public: +    void startTimer(); +    void stopTimer(); +    bool isRunning(); +    BOOL tick(); +}; + +class LLLocalGLTFMaterialMgr : public LLSingleton<LLLocalGLTFMaterialMgr> +{ +    LLSINGLETON(LLLocalGLTFMaterialMgr); +    ~LLLocalGLTFMaterialMgr(); +public: +    bool         addUnit(); +    void         delUnit(LLUUID tracking_id); +    bool         checkTextureDimensions(std::string filename); + +    LLUUID       getWorldID(LLUUID tracking_id); +    bool         isLocal(LLUUID world_id); +    std::string  getFilename(LLUUID tracking_id); + +    void         feedScrollList(LLScrollListCtrl* ctrl); +    void         doUpdates(); +    void         setNeedsRebake(); +    void         doRebake(); + +private: +    std::list<LLLocalGLTFMaterial*>    mMaterialList; +    LLLocalGLTFMaterialTimer           mTimer; +    bool                         mNeedsRebake; +    typedef std::list<LLLocalGLTFMaterial*>::iterator local_list_iter; +}; + +#endif // LL_LOCALRENDERMATERIALS_H + diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 7b17fb5fdf..9743976e33 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -55,6 +55,7 @@  #include "llfloaterperms.h"  #include "tinygltf/tiny_gltf.h" +#include "lltinygltfhelper.h"  #include <strstream> @@ -1046,38 +1047,6 @@ void LLMaterialFilePicker::notify(const std::vector<std::string>& filenames)      }  } -const tinygltf::Image* get_image_from_texture_index(const tinygltf::Model& model, S32 texture_index) -{ -    if (texture_index >= 0) -    { -        S32 source_idx = model.textures[texture_index].source; -        if (source_idx >= 0) -        { -            return &(model.images[source_idx]); -        } -    } - -    return nullptr; -} - -static LLImageRaw* get_texture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name) -{ -    const tinygltf::Image* image = get_image_from_texture_index(model, texture_index); -    LLImageRaw* rawImage = nullptr; - -    if (image != nullptr &&  -        image->bits == 8 && -        !image->image.empty() && -        image->component <= 4) -    { -        name = image->name; -        rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component); -        rawImage->verticalFlip(); -    } - -    return rawImage; -} -  static void strip_alpha_channel(LLPointer<LLImageRaw>& img)  {      if (img->getComponents() == 4) @@ -1108,16 +1077,12 @@ static void copy_red_channel(LLPointer<LLImageRaw>& src_img, LLPointer<LLImageRa      }  } -static void pack_textures(tinygltf::Model& model, tinygltf::Material& material,  +static void pack_textures(      LLPointer<LLImageRaw>& albedo_img,      LLPointer<LLImageRaw>& normal_img,      LLPointer<LLImageRaw>& mr_img,      LLPointer<LLImageRaw>& emissive_img,      LLPointer<LLImageRaw>& occlusion_img, -    LLPointer<LLViewerFetchedTexture>& albedo_tex, -    LLPointer<LLViewerFetchedTexture>& normal_tex, -    LLPointer<LLViewerFetchedTexture>& mr_tex, -    LLPointer<LLViewerFetchedTexture>& emissive_tex,      LLPointer<LLImageJ2C>& albedo_j2c,      LLPointer<LLImageJ2C>& normal_j2c,      LLPointer<LLImageJ2C>& mr_j2c, @@ -1125,70 +1090,25 @@ static void pack_textures(tinygltf::Model& model, tinygltf::Material& material,  {      if (albedo_img)      { -        albedo_tex = LLViewerTextureManager::getFetchedTexture(albedo_img, FTType::FTT_LOCAL_FILE, true);          albedo_j2c = LLViewerTextureList::convertToUploadFile(albedo_img);      }      if (normal_img)      { -        strip_alpha_channel(normal_img); -        normal_tex = LLViewerTextureManager::getFetchedTexture(normal_img, FTType::FTT_LOCAL_FILE, true);          normal_j2c = LLViewerTextureList::convertToUploadFile(normal_img);      }      if (mr_img)      { -        strip_alpha_channel(mr_img); - -        if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index) -        { -            // occlusion is a distinct texture from pbrMetallicRoughness -            // pack into mr red channel -            int occlusion_idx = material.occlusionTexture.index; -            int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index; -            if (occlusion_idx != mr_idx) -            { -                //scale occlusion image to match resolution of mr image -                occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); -              -                copy_red_channel(occlusion_img, mr_img); -            } -        } -    } -    else if (occlusion_img) -    { -        //no mr but occlusion exists, make a white mr_img and copy occlusion red channel over -        mr_img = new LLImageRaw(occlusion_img->getWidth(), occlusion_img->getHeight(), 3); -        mr_img->clear(255, 255, 255); -        copy_red_channel(occlusion_img, mr_img); - -    } - -    if (mr_img) -    { -        mr_tex = LLViewerTextureManager::getFetchedTexture(mr_img, FTType::FTT_LOCAL_FILE, true);          mr_j2c = LLViewerTextureList::convertToUploadFile(mr_img);      }      if (emissive_img)      { -        strip_alpha_channel(emissive_img); -        emissive_tex = LLViewerTextureManager::getFetchedTexture(emissive_img, FTType::FTT_LOCAL_FILE, true);          emissive_j2c = LLViewerTextureList::convertToUploadFile(emissive_img);      }  } -static LLColor4 get_color(const std::vector<double>& in) -{ -    LLColor4 out; -    for (S32 i = 0; i < llmin((S32) in.size(), 4); ++i) -    { -        out.mV[i] = in[i]; -    } - -    return out; -} -  void LLMaterialFilePicker::textureLoadedCallback(BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata)  {  } @@ -1240,23 +1160,24 @@ void LLMaterialFilePicker::loadMaterial(const std::string& filename)      model_out.materials.resize(1);      // get albedo texture -    LLPointer<LLImageRaw> albedo_img = get_texture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mME->mAlbedoName); +    LLPointer<LLImageRaw> albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mME->mAlbedoName);      // get normal map -    LLPointer<LLImageRaw> normal_img = get_texture(folder, model_in, material_in.normalTexture.index, mME->mNormalName); +    LLPointer<LLImageRaw> normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index, mME->mNormalName);      // get metallic-roughness texture -    LLPointer<LLImageRaw> mr_img = get_texture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mME->mMetallicRoughnessName); +    LLPointer<LLImageRaw> mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mME->mMetallicRoughnessName);      // get emissive texture -    LLPointer<LLImageRaw> emissive_img = get_texture(folder, model_in, material_in.emissiveTexture.index, mME->mEmissiveName); +    LLPointer<LLImageRaw> emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index, mME->mEmissiveName);      // get occlusion map if needed      LLPointer<LLImageRaw> occlusion_img;      if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index)      {          std::string tmp; -        occlusion_img = get_texture(folder, model_in, material_in.occlusionTexture.index, tmp); +        occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index, tmp);      } -    pack_textures(model_in, material_in, albedo_img, normal_img, mr_img, emissive_img, occlusion_img, -        mME->mAlbedoFetched, mME->mNormalFetched, mME->mMetallicRoughnessFetched, mME->mEmissiveFetched, +    LLTinyGLTFHelper::initFetchedTextures(material_in, albedo_img, normal_img, mr_img, emissive_img, occlusion_img, +        mME->mAlbedoFetched, mME->mNormalFetched, mME->mMetallicRoughnessFetched, mME->mEmissiveFetched); +    pack_textures(albedo_img, normal_img, mr_img, emissive_img, occlusion_img,          mME->mAlbedoJ2C, mME->mNormalJ2C, mME->mMetallicRoughnessJ2C, mME->mEmissiveJ2C);      LLUUID albedo_id; @@ -1389,8 +1310,8 @@ bool LLMaterialEditor::setFromGltfModel(tinygltf::Model& model, bool set_texture          setAlphaMode(material_in.alphaMode);          setAlphaCutoff(material_in.alphaCutoff); -        setAlbedoColor(get_color(material_in.pbrMetallicRoughness.baseColorFactor)); -        setEmissiveColor(get_color(material_in.emissiveFactor)); +        setAlbedoColor(LLTinyGLTFHelper::getColor(material_in.pbrMetallicRoughness.baseColorFactor)); +        setEmissiveColor(LLTinyGLTFHelper::getColor(material_in.emissiveFactor));          setMetalnessFactor(material_in.pbrMetallicRoughness.metallicFactor);          setRoughnessFactor(material_in.pbrMetallicRoughness.roughnessFactor); diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp new file mode 100644 index 0000000000..935f8e7794 --- /dev/null +++ b/indra/newview/lltinygltfhelper.cpp @@ -0,0 +1,245 @@ +/** + * @file   lltinygltfhelper.cpp + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lltinygltfhelper.h" + +#include "llimage.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" + +void strip_alpha_channel(LLPointer<LLImageRaw>& img) +{ +    if (img->getComponents() == 4) +    { +        LLImageRaw* tmp = new LLImageRaw(img->getWidth(), img->getHeight(), 3); +        tmp->copyUnscaled4onto3(img); +        img = tmp; +    } +} + +// copy red channel from src_img to dst_img +// PRECONDITIONS: +// dst_img must be 3 component +// src_img and dst_image must have the same dimensions +void copy_red_channel(LLPointer<LLImageRaw>& src_img, LLPointer<LLImageRaw>& dst_img) +{ +    llassert(src_img->getWidth() == dst_img->getWidth() && src_img->getHeight() == dst_img->getHeight()); +    llassert(dst_img->getComponents() == 3); + +    U32 pixel_count = dst_img->getWidth() * dst_img->getHeight(); +    U8* src = src_img->getData(); +    U8* dst = dst_img->getData(); +    S8 src_components = src_img->getComponents(); + +    for (U32 i = 0; i < pixel_count; ++i) +    { +        dst[i * 3] = src[i * src_components]; +    } +} + +void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material, +    LLPointer<LLImageRaw>& albedo_img, +    LLPointer<LLImageRaw>& normal_img, +    LLPointer<LLImageRaw>& mr_img, +    LLPointer<LLImageRaw>& emissive_img, +    LLPointer<LLImageRaw>& occlusion_img, +    LLPointer<LLViewerFetchedTexture>& albedo_tex, +    LLPointer<LLViewerFetchedTexture>& normal_tex, +    LLPointer<LLViewerFetchedTexture>& mr_tex, +    LLPointer<LLViewerFetchedTexture>& emissive_tex) +{ +    if (albedo_img) +    { +        albedo_tex = LLViewerTextureManager::getFetchedTexture(albedo_img, FTType::FTT_LOCAL_FILE, true); +    } + +    if (normal_img) +    { +        strip_alpha_channel(normal_img); +        normal_tex = LLViewerTextureManager::getFetchedTexture(normal_img, FTType::FTT_LOCAL_FILE, true); +    } + +    if (mr_img) +    { +        strip_alpha_channel(mr_img); + +        if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index) +        { +            // occlusion is a distinct texture from pbrMetallicRoughness +            // pack into mr red channel +            int occlusion_idx = material.occlusionTexture.index; +            int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index; +            if (occlusion_idx != mr_idx) +            { +                //scale occlusion image to match resolution of mr image +                occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); + +                copy_red_channel(occlusion_img, mr_img); +            } +        } +    } +    else if (occlusion_img) +    { +        //no mr but occlusion exists, make a white mr_img and copy occlusion red channel over +        mr_img = new LLImageRaw(occlusion_img->getWidth(), occlusion_img->getHeight(), 3); +        mr_img->clear(255, 255, 255); +        copy_red_channel(occlusion_img, mr_img); +    } + +    if (mr_img) +    { +        mr_tex = LLViewerTextureManager::getFetchedTexture(mr_img, FTType::FTT_LOCAL_FILE, true); +    } + +    if (emissive_img) +    { +        strip_alpha_channel(emissive_img); +        emissive_tex = LLViewerTextureManager::getFetchedTexture(emissive_img, FTType::FTT_LOCAL_FILE, true); +    } +} + +void LLTinyGLTFHelper::setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model) +{ +    S32 index; + +    auto& material_in = model.materials[0]; + +    // get albedo texture +    index = material_in.pbrMetallicRoughness.baseColorTexture.index; +    if (index >= 0) +    { +        mat->mAlbedoId.set(model.images[index].uri); +    } +    else +    { +        mat->mAlbedoId.setNull(); +    } + +    // get normal map +    index = material_in.normalTexture.index; +    if (index >= 0) +    { +        mat->mNormalId.set(model.images[index].uri); +    } +    else +    { +        mat->mNormalId.setNull(); +    } + +    // get metallic-roughness texture +    index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index; +    if (index >= 0) +    { +        mat->mMetallicRoughnessId.set(model.images[index].uri); +    } +    else +    { +        mat->mMetallicRoughnessId.setNull(); +    } + +    // get emissive texture +    index = material_in.emissiveTexture.index; +    if (index >= 0) +    { +        mat->mEmissiveId.set(model.images[index].uri); +    } +    else +    { +        mat->mEmissiveId.setNull(); +    } + +    mat->setAlphaMode(material_in.alphaMode); +    mat->mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f); + +    mat->mAlbedoColor = getColor(material_in.pbrMetallicRoughness.baseColorFactor); +    mat->mEmissiveColor = getColor(material_in.emissiveFactor); + +    mat->mMetallicFactor = llclamp((F32)material_in.pbrMetallicRoughness.metallicFactor, 0.f, 1.f); +    mat->mRoughnessFactor = llclamp((F32)material_in.pbrMetallicRoughness.roughnessFactor, 0.f, 1.f); + +    mat->mDoubleSided = material_in.doubleSided; +} + +LLColor4 LLTinyGLTFHelper::getColor(const std::vector<double>& in) +{ +    LLColor4 out; +    for (S32 i = 0; i < llmin((S32)in.size(), 4); ++i) +    { +        out.mV[i] = in[i]; +    } + +    return out; +} + +const tinygltf::Image * LLTinyGLTFHelper::getImageFromTextureIndex(const tinygltf::Model & model, S32 texture_index) +{ +    if (texture_index >= 0) +    { +        S32 source_idx = model.textures[texture_index].source; +        if (source_idx >= 0) +        { +            return &(model.images[source_idx]); +        } +    } + +    return nullptr; +} + +LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, std::string & name) +{ +    const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index); +    LLImageRaw* rawImage = nullptr; + +    if (image != nullptr && +        image->bits == 8 && +        !image->image.empty() && +        image->component <= 4) +    { +        name = image->name; +        rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component); +        rawImage->verticalFlip(); +    } + +    return rawImage; +} + +LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index) +{ +    const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index); +    LLImageRaw* rawImage = nullptr; + +    if (image != nullptr && +        image->bits == 8 && +        !image->image.empty() && +        image->component <= 4) +    { +        rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component); +        rawImage->verticalFlip(); +    } + +    return rawImage; +} diff --git a/indra/newview/lltinygltfhelper.h b/indra/newview/lltinygltfhelper.h new file mode 100644 index 0000000000..a25fdac41d --- /dev/null +++ b/indra/newview/lltinygltfhelper.h @@ -0,0 +1,55 @@ +/** + * @file   lltinygltfhelper.h + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + + +#pragma once + +#include "llgltfmaterial.h" +#include "llpointer.h" +#include "tinygltf/tiny_gltf.h" + +class LLImageRaw; +class LLViewerFetchedTexture; + +namespace LLTinyGLTFHelper +{ +    void setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model); +    LLColor4 getColor(const std::vector<double>& in); +    const tinygltf::Image* getImageFromTextureIndex(const tinygltf::Model& model, S32 texture_index); +    LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name); +    LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index); + +    void initFetchedTextures(tinygltf::Material& material, +        LLPointer<LLImageRaw>& albedo_img, +        LLPointer<LLImageRaw>& normal_img, +        LLPointer<LLImageRaw>& mr_img, +        LLPointer<LLImageRaw>& emissive_img, +        LLPointer<LLImageRaw>& occlusion_img, +        LLPointer<LLViewerFetchedTexture>& albedo_tex, +        LLPointer<LLViewerFetchedTexture>& normal_tex, +        LLPointer<LLViewerFetchedTexture>& mr_tex, +        LLPointer<LLViewerFetchedTexture>& emissive_tex); +} + diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index fead2e52b2..99394e550c 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -1,10 +1,10 @@  /**  - * @file llviewertexturelinumimagest.h + * @file llviewertexturelist.h   * @brief Object for managing the list of images within a region   * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, Linden Research, Inc.   *    * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public  | 
