diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 5daba1b966..44f32c1c5d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -12,13 +12,10 @@ jobs: strategy: matrix: runner: [windows-large, macos-12-xl] - configuration: [Release, ReleaseOS] + configuration: [Release] include: - runner: macos-12-xl developer_dir: "/Applications/Xcode_14.0.1.app/Contents/Developer" - exclude: - - runner: macos-12-xl - configuration: ReleaseOS runs-on: ${{ matrix.runner }} outputs: viewer_channel: ${{ steps.build.outputs.viewer_channel }} @@ -100,7 +97,7 @@ jobs: - name: Determine source branch id: which-branch - uses: secondlife/viewer-build-util/which-branch@v1 + uses: secondlife/viewer-build-util/which-branch@v2 with: token: ${{ github.token }} @@ -270,7 +267,7 @@ jobs: steps: - name: Sign and package Windows viewer if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID - uses: secondlife/viewer-build-util/sign-pkg-windows@v1 + uses: secondlife/viewer-build-util/sign-pkg-windows@v2 with: vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}" cert_name: "${{ env.AZURE_CERT_NAME }}" @@ -309,7 +306,7 @@ jobs: - name: Sign and package Mac viewer if: env.SIGNING_CERT_MACOS && env.SIGNING_CERT_MACOS_IDENTITY && env.SIGNING_CERT_MACOS_PASSWORD && steps.note-creds.outputs.note_user && steps.note-creds.outputs.note_pass && steps.note-creds.outputs.note_team - uses: secondlife/viewer-build-util/sign-pkg-mac@v1 + uses: secondlife/viewer-build-util/sign-pkg-mac@v2 with: channel: ${{ needs.build.outputs.viewer_channel }} imagename: ${{ needs.build.outputs.imagename }} @@ -329,7 +326,7 @@ jobs: steps: - name: Post Windows symbols if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS - uses: secondlife/viewer-build-util/post-bugsplat-windows@v1 + uses: secondlife/viewer-build-util/post-bugsplat-windows@v2 with: username: ${{ env.BUGSPLAT_USER }} password: ${{ env.BUGSPLAT_PASS }} @@ -346,7 +343,7 @@ jobs: steps: - name: Post Mac symbols if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS - uses: secondlife/viewer-build-util/post-bugsplat-mac@v1 + uses: secondlife/viewer-build-util/post-bugsplat-mac@v2 with: username: ${{ env.BUGSPLAT_USER }} password: ${{ env.BUGSPLAT_PASS }} @@ -359,31 +356,20 @@ jobs: runs-on: ubuntu-latest if: github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life_') steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: - name: Windows-installer + pattern: "*-installer" - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: - name: macOS-installer - - - uses: actions/download-artifact@v3 - with: - name: Windows-metadata - - - name: Rename windows metadata + pattern: "*-metadata" + + - name: Rename metadata run: | - mv autobuild-package.xml Windows-autobuild-package.xml - mv newview/viewer_version.txt Windows-viewer_version.txt - - - uses: actions/download-artifact@v3 - with: - name: macOS-metadata - - - name: Rename macOS metadata - run: | - mv autobuild-package.xml macOS-autobuild-package.xml - mv newview/viewer_version.txt macOS-viewer_version.txt + cp Windows-metadata/autobuild-package.xml Windows-autobuild-package.xml + cp Windows-metadata/newview/viewer_version.txt Windows-viewer_version.txt + cp macOS-metadata/autobuild-package.xml macOS-autobuild-package.xml + cp macOS-metadata/newview/viewer_version.txt macOS-viewer_version.txt # forked from softprops/action-gh-release - name: Create GitHub release @@ -406,8 +392,8 @@ jobs: append_body: true fail_on_unmatched_files: true files: | - *.dmg - *.exe + macOS-installer/*.dmg + Windows-installer/*.exe *-autobuild-package.xml *-viewer_version.txt diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml index b4b2565889..3f4bf21864 100644 --- a/.github/workflows/cla.yaml +++ b/.github/workflows/cla.yaml @@ -19,7 +19,7 @@ jobs: PERSONAL_ACCESS_TOKEN: ${{ secrets.SHARED_CLA_TOKEN }} with: branch: main - path-to-document: https://github.com/secondlife/cla/blob/master/CLA.md + path-to-document: https://github.com/secondlife/cla/blob/main/CLA.md path-to-signatures: signatures.json remote-organization-name: secondlife remote-repository-name: cla-signatures diff --git a/autobuild.xml b/autobuild.xml index 09ecde62ee..e8fd52e012 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -753,7 +753,7 @@ copyright Copyright 2014 Apache OpenOffice software version - None + 1.a01bb6c name dictionaries description @@ -1102,11 +1102,11 @@ archive hash - 6604c1cca515d287e697997a8d5593d1cae172a9 + 066625e7aa7f697a4b6cd461aad960c57181011f hash_algorithm sha1 url - https://github.com/secondlife/3p-glh_linear/releases/download/v1.0.1-dev2.g3253ed7-3253ed7/glh_linear-common-None.tar.zst + https://github.com/secondlife/3p-glh_linear/releases/download/v1.0.1-dev4-984c397/glh_linear-1.0.1-dev4-common-984c397.tar.zst name common @@ -1119,7 +1119,7 @@ copyright Copyright (c) 2000 Cass Everitt version - None + 1.0.1-dev4 name glh_linear description @@ -1194,11 +1194,11 @@ creds github hash - a193ff65d6db48626d65d96c6124c6efca85e8ec + ae2c2a215b1bc2e3f37a67e301926dc405902d1a hash_algorithm sha1 url - https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912596 + https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/136778143 name darwin64 @@ -1222,11 +1222,11 @@ creds github hash - ebfb82b6143874e7938b9d1e8a70d0a2e28aa818 + 0393dd75c58f7046bed47e62a8884a78cb02a5c3 hash_algorithm sha1 url - https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/108912599 + https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/136778145 name windows64 @@ -1765,6 +1765,15 @@ llca + copyright + Copyright (c) 2016, Linden Research, Inc.; data provided by the Mozilla NSS Project. + + license + mit + license_file + LICENSES/ca-license.txt + name + llca platforms common @@ -1772,27 +1781,18 @@ archive hash - 3a3e14563cd5fc019c3f139b82aa46ec79847709 + a9503e1b4e1d9790cf29d18a3d9ab39e6a515679 hash_algorithm sha1 url - https://github.com/secondlife/llca/releases/download/v202312051403.17-0f5d9c3/llca-202312051404.0-common-0f5d9c3.tar.zst + https://github.com/secondlife/llca/releases/download/v202402012004.0-0f5d9c3/llca-202402012004.0-common-0f5d9c3.tar.zst name common - license - mit - license_file - LICENSES/ca-license.txt - copyright - Copyright (c) 2016, Linden Research, Inc.; data provided by the Mozilla NSS Project. - version - 202312051404.0 - name - llca + 202402012004.0 llphysicsextensions_source diff --git a/build.sh b/build.sh index 58d7b73ab6..05f6e038e3 100755 --- a/build.sh +++ b/build.sh @@ -82,7 +82,7 @@ installer_Linux() { local package_name="$1" local package_dir="$(build_dir_Linux)/newview/" - local pattern=".*$(viewer_channel_suffix ${package_name})_[0-9]+_[0-9]+_[0-9]+_[0-9]+_i686\\.tar\\.bz2\$" + local pattern=".*$(viewer_channel_suffix ${package_name})_[0-9]+_[0-9]+_[0-9]+_[0-9]+_i686\\.tar\\.xz\$" # since the additional packages are built after the base package, # sorting oldest first ensures that the unqualified package is returned # even if someone makes a qualified name that duplicates the last word of the base name @@ -170,7 +170,7 @@ pre_build() # This name is consumed by indra/newview/CMakeLists.txt. Make it # absolute because we've had troubles with relative pathnames. abs_build_dir="$(cd "$build_dir"; pwd)" - VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/newview/$variant/secondlife-symbols-$symplat-${AUTOBUILD_ADDRSIZE}.tar.bz2")" + VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/newview/$variant/secondlife-symbols-$symplat-${AUTOBUILD_ADDRSIZE}.tar.xz")" fi # honor autobuild_configure_parameters same as sling-buildscripts @@ -414,10 +414,10 @@ do fi if [ -d "$build_dir/doxygen/html" ] then - tar -c -f "$build_dir/viewer-doxygen.tar.bz2" --strip-components 3 "$build_dir/doxygen/html" - python_cmd "$helpers/codeticket.py" addoutput "Doxygen Tarball" "$build_dir/viewer-doxygen.tar.bz2" \ + tar -cJf "$build_dir/viewer-doxygen.tar.xz" --strip-components 3 "$build_dir/doxygen/html" + python_cmd "$helpers/codeticket.py" addoutput "Doxygen Tarball" "$build_dir/viewer-doxygen.tar.xz" \ || fatal "Upload of doxygen tarball failed" - metadata+=("$build_dir/viewer-doxygen.tar.bz2") + metadata+=("$build_dir/viewer-doxygen.tar.xz") fi ;; *) diff --git a/doc/contributions.txt b/doc/contributions.txt index a1865e7732..ed1db26203 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -64,6 +64,8 @@ Aimee Trescothick VWR-14711 VWR-14712 VWR-15454 +AiraYumi + SL-20781 (github PR #613) Alejandro Rosenthal VWR-1184 Aleric Inglewood @@ -855,6 +857,7 @@ Kadah Coba Jondan Lundquist Joosten Briebers MAINT-7074 + BUG-225288 Josef Munster Josette Windlow Juilan Tripsa diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 91ce4808c3..affe94853a 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -24,12 +24,6 @@ * $/LicenseInfo$ */ -#if LL_MSVC -// disable warning about boost::lexical_cast returning uninitialized data -// when it fails to parse the string -#pragma warning (disable:4701) -#endif - #include "linden_common.h" #include "llavatarappearance.h" @@ -46,14 +40,6 @@ #include "boost/bind.hpp" #include "boost/tokenizer.hpp" - -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif - -#include - using namespace LLAvatarAppearanceDefines; //----------------------------------------------------------------------------- @@ -230,7 +216,7 @@ void LLAvatarAppearance::initInstance() for (U32 lod = 0; lod < mesh_dict->mLOD; lod++) { LLAvatarJointMesh* mesh = createAvatarJointMesh(); - std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast(lod); + std::string mesh_name = "m" + mesh_dict->mName + std::to_string(lod); // We pre-pended an m - need to capitalize first character for camelCase mesh_name[1] = toupper(mesh_name[1]); mesh->setName(mesh_name); diff --git a/indra/llcommon/lldoubledispatch.h b/indra/llcommon/lldoubledispatch.h index 8ed295b6f1..ce6731e864 100644 --- a/indra/llcommon/lldoubledispatch.h +++ b/indra/llcommon/lldoubledispatch.h @@ -255,7 +255,7 @@ private: }; /// shared_ptr manages Entry lifespan for us - typedef boost::shared_ptr EntryPtr; + typedef std::shared_ptr EntryPtr; /// use a @c list to make it easy to insert typedef std::list DispatchTable; DispatchTable mDispatch; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 4c749e8ce6..908a57600a 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -1081,7 +1081,7 @@ namespace LLError // // NOTE!!! Requires external mutex lock!!! template - std::pair, Recorders::iterator> + std::pair, Recorders::iterator> findRecorderPos(SettingsConfigPtr &s) { // Since we promise to return an iterator, use a classic iterator @@ -1092,7 +1092,7 @@ namespace LLError // *it is a RecorderPtr, a shared_ptr. Use a // dynamic_pointer_cast to try to downcast to test if it's also a // shared_ptr. - auto ptr = boost::dynamic_pointer_cast(*it); + auto ptr = std::dynamic_pointer_cast(*it); if (ptr) { // found the entry we want @@ -1112,7 +1112,7 @@ namespace LLError // shared_ptr might be empty (operator!() returns true) if there was no // such RECORDER subclass instance in mRecorders. template - boost::shared_ptr findRecorder() + std::shared_ptr findRecorder() { SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); LLMutexLock lock(&s->mRecorderMutex); @@ -1145,7 +1145,7 @@ namespace LLError if (!file_name.empty()) { - boost::shared_ptr recordToFile(new RecordToFile(file_name)); + std::shared_ptr recordToFile(new RecordToFile(file_name)); if (recordToFile->okay()) { addRecorder(recordToFile); diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 57f10b7895..77b187a80f 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -174,7 +174,7 @@ namespace LLError bool mWantsMultiline; }; - typedef boost::shared_ptr RecorderPtr; + typedef std::shared_ptr RecorderPtr; /** * Instantiate GenericRecorder with a callable(level, message) to get diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 1a305ec3dc..70931f3a65 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -211,12 +211,21 @@ void LLEventPumps::clear() } } -void LLEventPumps::reset() +void LLEventPumps::reset(bool log_pumps) { // Reset every known LLEventPump instance. Leave it up to each instance to // decide what to do with the reset() call. + if (log_pumps) + { + LL_INFOS() << "Resetting " << (S32)mPumpMap.size() << " pumps" << LL_ENDL; + } + for (PumpMap::value_type& pair : mPumpMap) { + if (log_pumps) + { + LL_INFOS() << "Resetting pump " << pair.first << LL_ENDL; + } pair.second->reset(); } } @@ -373,9 +382,11 @@ std::string LLEventPump::inventName(const std::string& pfx) void LLEventPump::clear() { + LLMutexLock lock(&mConnectionListMutex); // Destroy the original LLStandardSignal instance, replacing it with a // whole new one. mSignal = std::make_shared(); + mConnections.clear(); } @@ -383,6 +394,7 @@ void LLEventPump::reset() { // Resetting mSignal is supposed to disconnect everything on its own // But due to crash on 'reset' added explicit cleanup to get more data + LLMutexLock lock(&mConnectionListMutex); ConnectionMap::const_iterator iter = mConnections.begin(); ConnectionMap::const_iterator end = mConnections.end(); while (iter!=end) @@ -407,6 +419,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL return LLBoundListener(); } + LLMutexLock lock(&mConnectionListMutex); + float nodePosition = 1.0; // if the supplied name is empty we are not interested in the ordering mechanism @@ -566,8 +580,9 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL return bound; } -LLBoundListener LLEventPump::getListener(const std::string& name) const +LLBoundListener LLEventPump::getListener(const std::string& name) { + LLMutexLock lock(&mConnectionListMutex); ConnectionMap::const_iterator found = mConnections.find(name); if (found != mConnections.end()) { @@ -579,6 +594,7 @@ LLBoundListener LLEventPump::getListener(const std::string& name) const void LLEventPump::stopListening(const std::string& name) { + LLMutexLock lock(&mConnectionListMutex); ConnectionMap::iterator found = mConnections.find(name); if (found != mConnections.end()) { diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 34fb9ff246..168846c4cd 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -334,7 +334,7 @@ public: * Reset all known LLEventPump instances * workaround for DEV-35406 crash on shutdown */ - void reset(); + void reset(bool log_pumps = false); private: friend class LLEventPump; @@ -560,7 +560,7 @@ public: /// Get the LLBoundListener associated with the passed name (dummy /// LLBoundListener if not found) - virtual LLBoundListener getListener(const std::string& name) const; + virtual LLBoundListener getListener(const std::string& name); /** * Instantiate one of these to block an existing connection: * @code @@ -603,6 +603,7 @@ private: LLHandle mRegistry; std::string mName; + LLMutex mConnectionListMutex; protected: virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 9edc7e40f3..e0d0ab9ac7 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -627,7 +627,7 @@ namespace LLInitParam UserData* mUserData; }; - typedef boost::shared_ptr ParamDescriptorPtr; + typedef std::shared_ptr ParamDescriptorPtr; // each derived Block class keeps a static data structure maintaining offsets to various params class LL_COMMON_API BlockDescriptor diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index 8f88e728ce..b2b1162f63 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -462,10 +462,10 @@ private: LLProcessPtr mChild; LLTempBoundListener mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection; - boost::scoped_ptr mBlocker; + std::unique_ptr mBlocker; LLProcess::ReadPipe::size_type mExpect; LLError::RecorderPtr mRecorder; - boost::scoped_ptr mListener; + std::unique_ptr mListener; }; // These must follow the declaration of LLLeapImpl, so they may as well be last. diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 2a3f1c68a3..574b9b8b3b 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -38,6 +38,7 @@ #include #elif LL_LINUX # include +# include #endif #include "llmemory.h" @@ -270,72 +271,21 @@ U64 LLMemory::getCurrentRSS() } #elif defined(LL_LINUX) -// Linux RSS appears to have drifted from the implementation below. -// U64 LLMemory::getCurrentRSS() -// { -// static const char statPath[] = "/proc/self/stat"; -// LLFILE *fp = LLFile::fopen(statPath, "r"); -// U64 rss = 0; -// if (fp == NULL) -// { -// LL_WARNS() << "couldn't open " << statPath << LL_ENDL; -// return 0; -// } +U64 LLMemory::getCurrentRSS() +{ + struct rusage usage; -// // Eee-yew! See Documentation/filesystems/proc.txt in your -// // nearest friendly kernel tree for details. - -// { -// int ret = fscanf(fp, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*d %*d " -// "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %Lu", -// &rss); -// if (ret != 1) -// { -// LL_WARNS() << "couldn't parse contents of " << statPath << LL_ENDL; -// rss = 0; -// } -// } - -// fclose(fp); + if (getrusage(RUSAGE_SELF, &usage) != 0) { + // Error handling code could be here + return 0; + } -// return rss; -// } -#include -#include -#include -#include -#include -#include - -// return the RSS in bytes. This value is converted to kilobytes implicitly elsewhere. -U64 LLMemory::getCurrentRSS() { - namespace fs = std::filesystem; - - // Get the page size (static variable) - static const long pageSize = sysconf(_SC_PAGESIZE); - - // Open the /proc/self/statm file - static const auto statmPath = fs::path("/proc/self/statm"); - std::ifstream statmFile(statmPath); - if (!statmFile.is_open()) { - return 0; // Return 0 if the file cannot be opened - } - - // Read the entire line from statm file - std::string line; - std::getline(statmFile, line); - statmFile.close(); - - // Extract the values from the line - std::istringstream iss(line); - long size, rss, shared, text, lib, data, dt; - iss >> size >> rss >> shared >> text >> lib >> data >> dt; - - // Convert pages to bytes and return RSS - return static_cast( rss * pageSize ); + // ru_maxrss (since Linux 2.6.32) + // This is the maximum resident set size used (in kilobytes). + return usage.ru_maxrss * 1024; } -// + #else U64 LLMemory::getCurrentRSS() diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 0d65762284..0d6a147da3 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -36,7 +36,6 @@ #include "llevents.h" #include "llexception.h" -#include #include #include #include @@ -587,7 +586,7 @@ LLProcess::LLProcess(const LLSDOrParams& params): // apr_procattr_child_err_set()), or accepting a filename, opening it and // passing that apr_file_t (simple <, >, 2> redirect emulation). std::vector select; - BOOST_FOREACH(const FileParam& fparam, params.files) + for (const FileParam& fparam : params.files) { // Every iteration, we're going to append an item to 'select'. At the // top of the loop, its size() is, in effect, an index. Use that to @@ -684,7 +683,7 @@ LLProcess::LLProcess(const LLSDOrParams& params): argv.push_back(params.executable().c_str()); // Add arguments. See above remarks about c_str(). - BOOST_FOREACH(const std::string& arg, params.args) + for (const std::string& arg : params.args) { argv.push_back(arg.c_str()); } @@ -961,7 +960,7 @@ void LLProcess::handle_status(int reason, int status) // only be performed if in fact we're going to produce the log message. LL_DEBUGS("LLProcess") << empty; std::string reason_str; - BOOST_FOREACH(const ReasonCode& rcp, reasons) + for (const ReasonCode& rcp : reasons) { if (reason == rcp.code) { @@ -1151,7 +1150,7 @@ std::ostream& operator<<(std::ostream& out, const LLProcess::Params& params) out << "cd " << LLStringUtil::quote(params.cwd) << ": "; } out << LLStringUtil::quote(params.executable); - BOOST_FOREACH(const std::string& arg, params.args) + for (const std::string& arg : params.args) { out << ' ' << LLStringUtil::quote(arg); } diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index 0842f2eb07..c57821bf52 100644 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -51,7 +51,7 @@ class LLEventPump; class LLProcess; /// LLProcess instances are created on the heap by static factory methods and /// managed by ref-counted pointers. -typedef boost::shared_ptr LLProcessPtr; +typedef std::shared_ptr LLProcessPtr; /** * LLProcess handles launching an external process with specified command line diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h index d610f86234..42e3d9b47a 100644 --- a/indra/llcommon/llrun.h +++ b/indra/llcommon/llrun.h @@ -48,7 +48,7 @@ public: /** * @brief The pointer to a runnable. */ - typedef boost::shared_ptr run_ptr_t; + typedef std::shared_ptr run_ptr_t; /** * @brief The handle for use in the API. diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index ad54d1b0be..fdcc052bd0 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -478,9 +478,9 @@ namespace llsd { /***************************************************************************** -* BOOST_FOREACH() helpers for LLSD +* range-based for-loop helpers for LLSD *****************************************************************************/ -/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... } +/// Usage: for (LLSD item : inArray(someLLSDarray)) { ... } class inArray { public: @@ -503,7 +503,7 @@ private: /// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator. typedef std::map::value_type MapEntry; -/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... } +/// Usage: for([const] MapEntry& e : inMap(someLLSDmap)) { ... } class inMap { public: diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 6b1986d0e9..5f1a89670e 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -32,7 +32,6 @@ #include "lldependencies.h" #include "llexception.h" #include "llcoros.h" -#include #include #include // std::cerr in dire emergency #include @@ -411,7 +410,7 @@ void LLSingletonBase::cleanup_() void LLSingletonBase::deleteAll() { // It's essential to traverse these in dependency order. - BOOST_FOREACH(LLSingletonBase* sp, dep_sort()) + for (LLSingletonBase* sp : dep_sort()) { // Capture the class name first: in case of exception, don't count on // being able to extract it later. diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 1eb512a5f8..3d8fe74c00 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1229,7 +1229,7 @@ void LLStringUtilBase::getTokens(const string_type& string, std::vector > instrp; + std::unique_ptr< LLStringUtilBaseImpl::InString > instrp; if (escapes.empty()) instrp.reset(new LLStringUtilBaseImpl::InString(string.begin(), string.end())); else diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index a25e33cdee..c2af17a5cf 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -49,7 +49,6 @@ #include "llsdutil.h" #include #include -#include #include #include #include @@ -917,9 +916,9 @@ void LLMemoryInfo::stream(std::ostream& s) const // Max key length size_t key_width(0); - BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) + for (const auto& [key, value] : inMap(mStatsMap)) { - size_t len(pair.first.length()); + size_t len(key.length()); if (len > key_width) { key_width = len; @@ -927,10 +926,9 @@ void LLMemoryInfo::stream(std::ostream& s) const } // Now stream stats - BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) + for (const auto& [key, value] : inMap(mStatsMap)) { - s << pfx << std::setw(narrow(key_width+1)) << (pair.first + ':') << ' '; - LLSD value(pair.second); + s << pfx << std::setw(narrow(key_width+1)) << (key + ':') << ' '; if (value.isInteger()) s << std::setw(12) << value.asInteger(); else if (value.isReal()) diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index d4ca7bce65..e3bf4c413f 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -156,27 +156,27 @@ namespace tut int countMessages() { - return boost::dynamic_pointer_cast(mRecorder)->countMessages(); + return std::dynamic_pointer_cast(mRecorder)->countMessages(); } void clearMessages() { - boost::dynamic_pointer_cast(mRecorder)->clearMessages(); + std::dynamic_pointer_cast(mRecorder)->clearMessages(); } void setWantsTime(bool t) { - boost::dynamic_pointer_cast(mRecorder)->showTime(t); + std::dynamic_pointer_cast(mRecorder)->showTime(t); } void setWantsMultiline(bool t) { - boost::dynamic_pointer_cast(mRecorder)->showMultiline(t); + std::dynamic_pointer_cast(mRecorder)->showMultiline(t); } std::string message(int n) { - return boost::dynamic_pointer_cast(mRecorder)->message(n); + return std::dynamic_pointer_cast(mRecorder)->message(n); } void ensure_message_count(int expectedCount) @@ -500,12 +500,12 @@ namespace void testLogName(LLError::RecorderPtr recorder, LogFromFunction f, const std::string& class_name = "") { - boost::dynamic_pointer_cast(recorder)->clearMessages(); + std::dynamic_pointer_cast(recorder)->clearMessages(); std::string name = f(false); f(true); - std::string messageWithoutName = boost::dynamic_pointer_cast(recorder)->message(0); - std::string messageWithName = boost::dynamic_pointer_cast(recorder)->message(1); + std::string messageWithoutName = std::dynamic_pointer_cast(recorder)->message(0); + std::string messageWithName = std::dynamic_pointer_cast(recorder)->message(1); ensure_has(name + " logged without name", messageWithoutName, name); @@ -694,13 +694,13 @@ namespace tut LL_INFOS() << "boo" << LL_ENDL; ensure_message_field_equals(0, MSG_FIELD, "boo"); - ensure_equals("alt recorder count", boost::dynamic_pointer_cast(altRecorder)->countMessages(), 1); - ensure_contains("alt recorder message 0", boost::dynamic_pointer_cast(altRecorder)->message(0), "boo"); + ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 1); + ensure_contains("alt recorder message 0", std::dynamic_pointer_cast(altRecorder)->message(0), "boo"); LLError::setTimeFunction(roswell); LLError::RecorderPtr anotherRecorder(new TestRecorder()); - boost::dynamic_pointer_cast(anotherRecorder)->showTime(true); + std::dynamic_pointer_cast(anotherRecorder)->showTime(true); LLError::addRecorder(anotherRecorder); LL_INFOS() << "baz" << LL_ENDL; @@ -708,10 +708,10 @@ namespace tut std::string when = roswell(); ensure_message_does_not_contain(1, when); - ensure_equals("alt recorder count", boost::dynamic_pointer_cast(altRecorder)->countMessages(), 2); - ensure_does_not_contain("alt recorder message 1", boost::dynamic_pointer_cast(altRecorder)->message(1), when); - ensure_equals("another recorder count", boost::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); - ensure_contains("another recorder message 0", boost::dynamic_pointer_cast(anotherRecorder)->message(0), when); + ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 2); + ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast(altRecorder)->message(1), when); + ensure_equals("another recorder count", std::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); + ensure_contains("another recorder message 0", std::dynamic_pointer_cast(anotherRecorder)->message(0), when); LLError::removeRecorder(altRecorder); LLError::removeRecorder(anotherRecorder); diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index 4a1d4b8ba9..5840cacd63 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -101,7 +101,7 @@ namespace tut int which; LLTestApp testApp; - void explicit_wait(boost::shared_ptr>& cbp); + void explicit_wait(std::shared_ptr>& cbp); void waitForEventOn1(); void coroPump(); void postAndWait1(); @@ -111,7 +111,7 @@ namespace tut typedef coroutine_group::object object; coroutine_group coroutinegrp("coroutine"); - void test_data::explicit_wait(boost::shared_ptr>& cbp) + void test_data::explicit_wait(std::shared_ptr>& cbp) { BEGIN { @@ -127,7 +127,7 @@ namespace tut // For test purposes, instead of handing 'callback' (or an // adapter) off to some I/O subsystem, we'll just pass it back to // our caller. - cbp = boost::make_shared>(); + cbp = std::make_shared>(); LLCoros::Future future = LLCoros::getFuture(*cbp); // calling get() on the future causes us to suspend @@ -146,7 +146,7 @@ namespace tut DEBUG; // Construct the coroutine instance that will run explicit_wait. - boost::shared_ptr> respond; + std::shared_ptr> respond; LLCoros::instance().launch("test<1>", [this, &respond](){ explicit_wait(respond); }); mSync.bump(); diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 5daa29adf4..95af9c2a50 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -94,7 +94,7 @@ namespace tut ensure("couldn't find stack Keyed", bool(found)); ensure_equals("found wrong Keyed instance", found.get(), &one); { - boost::scoped_ptr two(new Keyed("two")); + std::unique_ptr two(new Keyed("two")); ensure_equals(Keyed::instanceCount(), 2); auto found = Keyed::getInstance("two"); ensure("couldn't find heap Keyed", bool(found)); @@ -118,7 +118,7 @@ namespace tut std::weak_ptr found = one.getWeak(); ensure(! found.expired()); { - boost::scoped_ptr two(new Unkeyed); + std::unique_ptr two(new Unkeyed); ensure_equals(Unkeyed::instanceCount(), 2); } ensure_equals(Unkeyed::instanceCount(), 1); diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index b6b297b8d7..628f046f55 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -21,7 +21,6 @@ // external library headers #include "llapr.h" #include "apr_thread_proc.h" -#include #include #include #include @@ -323,7 +322,7 @@ namespace tut { /*==========================================================================*| std::string reason_str; - BOOST_FOREACH(const ReasonCode& rcp, reasons) + for (const ReasonCode& rcp : reasons) { if (reason == rcp.code) { @@ -554,7 +553,7 @@ namespace tut catch (const failure&) { std::cout << "History:\n"; - BOOST_FOREACH(const Item& item, history) + for (const Item& item : history) { std::string what(item.what); if ((! what.empty()) && what[what.length() - 1] == '\n') diff --git a/indra/llcommon/tests/llstreamqueue_test.cpp b/indra/llcommon/tests/llstreamqueue_test.cpp index 050ad5c5bf..8af057328b 100644 --- a/indra/llcommon/tests/llstreamqueue_test.cpp +++ b/indra/llcommon/tests/llstreamqueue_test.cpp @@ -15,9 +15,6 @@ #include "llstreamqueue.h" // STL headers #include -// std headers -// external library headers -#include // other Linden headers #include "../test/lltut.h" #include "stringize.h" @@ -133,7 +130,7 @@ namespace tut std::streamsize leave(5); // len("craft") above std::streamsize skip(total - leave); std::streamsize written(0); - BOOST_FOREACH(const std::string& block, blocks) + for (const std::string& block : blocks) { written += strq.write(&block[0], block.length()); ensure_equals("size() after write()", strq.size(), written); @@ -152,7 +149,7 @@ namespace tut { set_test_name("concatenate blocks"); std::string blocks[] = { "abcd", "efghij", "klmnopqrs" }; - BOOST_FOREACH(const std::string& block, blocks) + for (const std::string& block : blocks) { strq.write(&block[0], block.length()); } @@ -170,7 +167,7 @@ namespace tut { set_test_name("split blocks"); std::string blocks[] = { "abcdefghijklm", "nopqrstuvwxyz" }; - BOOST_FOREACH(const std::string& block, blocks) + for (const std::string& block : blocks) { strq.write(&block[0], block.length()); } diff --git a/indra/llcommon/tests/lltreeiterators_test.cpp b/indra/llcommon/tests/lltreeiterators_test.cpp index 1d619867d4..b9c7a70c07 100644 --- a/indra/llcommon/tests/lltreeiterators_test.cpp +++ b/indra/llcommon/tests/lltreeiterators_test.cpp @@ -38,7 +38,6 @@ // external library headers #include #include -#include // associated header #include "../lltreeiterators.h" @@ -402,7 +401,7 @@ private: * * Example: * @code - * BOOST_FOREACH(TreeNodePtr node, getRootRange(somenode)) + * for (TreeNodePtr node : getRootRange(somenode)) * { * std::cout << node->name() << '\n'; * } @@ -424,7 +423,7 @@ getRootRange(const TreeNodePtr& node) * * Example: * @code - * BOOST_FOREACH(TreeNodePtr node, getWalkRange(root)) + * for (TreeNodePtr node : getWalkRange(root)) * { * std::cout << node->name() << '\n'; * } @@ -520,7 +519,7 @@ public: * * Example usage: * @code - * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getRootRange()) + * for (EnhancedTreeNodePtr node : somenode->getRootRange()) * { * std::cout << node->name() << '\n'; * } @@ -564,7 +563,7 @@ public: * * Example usage: * @code - * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getWalkRange()) + * for (EnhancedTreeNodePtr node : somenode->getWalkRange()) * { * std::cout << node->name() << '\n'; * } @@ -644,7 +643,7 @@ LLLinkedIter PlainTree_child_end(PlainTree* node) * * Example: * @code - * BOOST_FOREACH(PlainTree* node, getRootRange(somenode)) + * for (PlainTree* node : getRootRange(somenode)) * { * std::cout << node->name() << '\n'; * } @@ -668,7 +667,7 @@ getRootRange(PlainTree* node) * * Example: * @code - * BOOST_FOREACH(PlainTree* node, getWalkRange(root)) + * for (PlainTree* node : getWalkRange(root)) * { * std::cout << node->name() << '\n'; * } @@ -1103,18 +1102,18 @@ namespace tut // This test function illustrates the looping techniques described in the // comments for the getRootRange() free function, the // EnhancedTreeNode::root_range template and the - // EnhancedTreeNode::getRootRange() method. Obviously the BOOST_FOREACH() + // EnhancedTreeNode::getRootRange() method. Obviously the for() // forms are more succinct. TreeNodePtr tnroot(example_tree()); TreeNodePtr tnB2b(get_B2b (tnroot, boost::bind(&TreeNode::child_begin, _1))); - std::string desc1("BOOST_FOREACH(TreeNodePr, getRootRange(tnB2b))"); + std::string desc1("for (TreeNodePr : getRootRange(tnB2b))"); // std::cout << desc1 << "\n"; // Although we've commented out the output statement, ensure that the // loop construct is still valid, as promised by the getRootRange() // documentation. - BOOST_FOREACH(TreeNodePtr node, getRootRange(tnB2b)) + for (TreeNodePtr node : getRootRange(tnB2b)) { // std::cout << node->name() << '\n'; } @@ -1137,9 +1136,9 @@ namespace tut // std::cout << (*ri)->name() << '\n'; } - std::string desc2("BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange())"); + std::string desc2("for (EnhancedTreeNodePtr node : etnB2b->getRootRange())"); // std::cout << desc2 << '\n'; - BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange()) + for (EnhancedTreeNodePtr node : etnB2b->getRootRange()) { // std::cout << node->name() << '\n'; } diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index d657b329bb..6978c296b3 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -218,12 +218,12 @@ public: /// for the sought string. std::string messageWith(const std::string& search, bool required=true) { - return boost::dynamic_pointer_cast(mRecorder)->messageWith(search, required); + return std::dynamic_pointer_cast(mRecorder)->messageWith(search, required); } std::ostream& streamto(std::ostream& out) const { - return boost::dynamic_pointer_cast(mRecorder)->streamto(out); + return std::dynamic_pointer_cast(mRecorder)->streamto(out); } friend inline std::ostream& operator<<(std::ostream& out, const CaptureLog& self) diff --git a/indra/llcorehttp/_httplibcurl.h b/indra/llcorehttp/_httplibcurl.h index a71eae59c0..61ecc492af 100644 --- a/indra/llcorehttp/_httplibcurl.h +++ b/indra/llcorehttp/_httplibcurl.h @@ -65,7 +65,7 @@ private: void operator=(const HttpLibcurl &); // Not defined public: - typedef boost::shared_ptr opReqPtr_t; + typedef std::shared_ptr opReqPtr_t; /// Give cycles to libcurl to run active requests. Completed /// operations (successful or failed) will be retried or handed diff --git a/indra/llcorehttp/_httpoperation.cpp b/indra/llcorehttp/_httpoperation.cpp index 3b64018132..c3a9bcaf54 100644 --- a/indra/llcorehttp/_httpoperation.cpp +++ b/indra/llcorehttp/_httpoperation.cpp @@ -58,7 +58,7 @@ HttpOperation::handleMap_t HttpOperation::mHandleMap; LLCoreInt::HttpMutex HttpOperation::mOpMutex; HttpOperation::HttpOperation(): - boost::enable_shared_from_this(), + std::enable_shared_from_this(), mReplyQueue(), mUserHandler(), mReqPolicy(HttpRequest::DEFAULT_POLICY_ID), diff --git a/indra/llcorehttp/_httpoperation.h b/indra/llcorehttp/_httpoperation.h index 8c1364bab4..b07ef76d49 100644 --- a/indra/llcorehttp/_httpoperation.h +++ b/indra/llcorehttp/_httpoperation.h @@ -69,12 +69,12 @@ class HttpService; /// and those interfaces establish the access rules. class HttpOperation : private boost::noncopyable, - public boost::enable_shared_from_this + public std::enable_shared_from_this { public: - typedef boost::shared_ptr ptr_t; - typedef boost::weak_ptr wptr_t; - typedef boost::shared_ptr HttpReplyQueuePtr_t; + typedef std::shared_ptr ptr_t; + typedef std::weak_ptr wptr_t; + typedef std::shared_ptr HttpReplyQueuePtr_t; /// Threading: called by consumer thread. HttpOperation(); @@ -157,12 +157,12 @@ public: HttpHandle getHandle(); template< class OPT > - static boost::shared_ptr< OPT > fromHandle(HttpHandle handle) + static std::shared_ptr< OPT > fromHandle(HttpHandle handle) { ptr_t ptr = findByHandle(handle); if (!ptr) - return boost::shared_ptr< OPT >(); - return boost::dynamic_pointer_cast< OPT >(ptr); + return std::shared_ptr< OPT >(); + return std::dynamic_pointer_cast< OPT >(ptr); } protected: diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 50317a8f0b..908b35ee36 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -203,7 +203,7 @@ HttpOpRequest::~HttpOpRequest() void HttpOpRequest::stageFromRequest(HttpService * service) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast(shared_from_this())); + HttpOpRequest::ptr_t self(std::dynamic_pointer_cast(shared_from_this())); service->getPolicy().addOp(self); // transfers refcount } @@ -211,7 +211,7 @@ void HttpOpRequest::stageFromRequest(HttpService * service) void HttpOpRequest::stageFromReady(HttpService * service) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; - HttpOpRequest::ptr_t self(boost::dynamic_pointer_cast(shared_from_this())); + HttpOpRequest::ptr_t self(std::dynamic_pointer_cast(shared_from_this())); service->getTransport().addOp(self); // transfers refcount } @@ -292,7 +292,7 @@ void HttpOpRequest::visitNotifier(HttpRequest * request) // HttpOpRequest::ptr_t HttpOpRequest::fromHandle(HttpHandle handle) // { // -// return boost::dynamic_pointer_cast((static_cast(handle))->shared_from_this()); +// return std::dynamic_pointer_cast((static_cast(handle))->shared_from_this()); // } diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h index 24f251c367..5396e7bf49 100644 --- a/indra/llcorehttp/_httpoprequest.h +++ b/indra/llcorehttp/_httpoprequest.h @@ -66,7 +66,7 @@ class BufferArray; class HttpOpRequest : public HttpOperation { public: - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; HttpOpRequest(); diff --git a/indra/llcorehttp/_httpopsetget.h b/indra/llcorehttp/_httpopsetget.h index eabd41e79f..04ab2446ef 100644 --- a/indra/llcorehttp/_httpopsetget.h +++ b/indra/llcorehttp/_httpopsetget.h @@ -53,7 +53,7 @@ namespace LLCore class HttpOpSetGet : public HttpOperation { public: - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; HttpOpSetGet(); diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h index 0b8806a3e2..955f757c93 100644 --- a/indra/llcorehttp/_httppolicy.h +++ b/indra/llcorehttp/_httppolicy.h @@ -60,7 +60,7 @@ private: void operator=(const HttpPolicy &); // Not defined public: - typedef boost::shared_ptr opReqPtr_t; + typedef std::shared_ptr opReqPtr_t; /// Threading: called by init thread. HttpRequest::policy_t createPolicyClass(); diff --git a/indra/llcorehttp/_httpreplyqueue.h b/indra/llcorehttp/_httpreplyqueue.h index 33e205c1c9..2de26249ef 100644 --- a/indra/llcorehttp/_httpreplyqueue.h +++ b/indra/llcorehttp/_httpreplyqueue.h @@ -63,8 +63,8 @@ class HttpReplyQueue : private boost::noncopyable { public: - typedef boost::shared_ptr opPtr_t; - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr opPtr_t; + typedef std::shared_ptr ptr_t; HttpReplyQueue(); virtual ~HttpReplyQueue(); diff --git a/indra/llcorehttp/_httprequestqueue.h b/indra/llcorehttp/_httprequestqueue.h index f0296f30e3..52369df174 100644 --- a/indra/llcorehttp/_httprequestqueue.h +++ b/indra/llcorehttp/_httprequestqueue.h @@ -61,7 +61,7 @@ private: void operator=(const HttpRequestQueue &); // Not defined public: - typedef boost::shared_ptr opPtr_t; + typedef std::shared_ptr opPtr_t; static void init(); static void term(); diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h index 18505e0aad..7fe5c48edf 100644 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -301,24 +301,24 @@ struct HttpStatus HttpStatus() { - mDetails = boost::shared_ptr
(new Details(LLCORE, HE_SUCCESS)); + mDetails = std::shared_ptr
(new Details(LLCORE, HE_SUCCESS)); } HttpStatus(type_enum_t type, short status) { - mDetails = boost::shared_ptr
(new Details(type, status)); + mDetails = std::shared_ptr
(new Details(type, status)); } HttpStatus(int http_status) { - mDetails = boost::shared_ptr
(new Details(http_status, + mDetails = std::shared_ptr
(new Details(http_status, (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR)); llassert(http_status >= 100 && http_status <= 999); } HttpStatus(int http_status, const std::string &message) { - mDetails = boost::shared_ptr
(new Details(http_status, + mDetails = std::shared_ptr
(new Details(http_status, (http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR)); llassert(http_status >= 100 && http_status <= 999); mDetails->mMessage = message; @@ -341,7 +341,7 @@ struct HttpStatus HttpStatus & clone(const HttpStatus &rhs) { - mDetails = boost::shared_ptr
(new Details(*rhs.mDetails)); + mDetails = std::shared_ptr
(new Details(*rhs.mDetails)); return *this; } @@ -490,14 +490,14 @@ private: LLSD mErrorData; }; - boost::shared_ptr
mDetails; + std::shared_ptr
mDetails; }; // end struct HttpStatus /// A namespace for several free methods and low level utilities. namespace LLHttp { - typedef boost::shared_ptr CURL_ptr; + typedef std::shared_ptr CURL_ptr; void initialize(); void cleanup(); diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h index 65e043f5d3..4cfb2598c7 100644 --- a/indra/llcorehttp/httphandler.h +++ b/indra/llcorehttp/httphandler.h @@ -58,8 +58,8 @@ class HttpResponse; class HttpHandler { public: - typedef boost::shared_ptr ptr_t; - typedef boost::weak_ptr wptr_t; + typedef std::shared_ptr ptr_t; + typedef std::weak_ptr wptr_t; virtual ~HttpHandler() { } diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h index b9168cb6ec..e7cf4037bf 100644 --- a/indra/llcorehttp/httpheaders.h +++ b/indra/llcorehttp/httpheaders.h @@ -85,7 +85,7 @@ public: typedef container_t::const_reverse_iterator const_reverse_iterator; typedef container_t::value_type value_type; typedef container_t::size_type size_type; - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; public: /// @post In addition to the instance, caller has a refcount diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index ef12edf316..2023e6a6f7 100644 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -60,7 +60,7 @@ class HttpOptions : private boost::noncopyable public: HttpOptions(); - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; virtual ~HttpOptions(); // Use release() diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h index ca4b9e92bc..857a034a7b 100644 --- a/indra/llcorehttp/httprequest.h +++ b/indra/llcorehttp/httprequest.h @@ -96,8 +96,8 @@ private: public: typedef unsigned int policy_t; - typedef boost::shared_ptr ptr_t; - typedef boost::weak_ptr wptr_t; + typedef std::shared_ptr ptr_t; + typedef std::weak_ptr wptr_t; public: /// @name PolicyMethods /// @{ @@ -627,7 +627,7 @@ public: protected: private: - typedef boost::shared_ptr HttpReplyQueuePtr_t; + typedef std::shared_ptr HttpReplyQueuePtr_t; /// @name InstanceData /// diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h index b834085e5c..ef98fbef2b 100644 --- a/indra/llcorehttp/httpresponse.h +++ b/indra/llcorehttp/httpresponse.h @@ -72,7 +72,7 @@ public: /// Statistics for the HTTP struct TransferStats { - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; TransferStats() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {} F64 mSizeDownload; diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index c95db90340..e21045f3b7 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -44,7 +44,6 @@ #include "stringize.h" #include "llstring.h" #include -#include #include #include #include @@ -746,10 +745,10 @@ void LLDir::walkSearchSkinDirs(const std::string& subdir, const std::string& filename, const FUNCTION& function) const { - BOOST_FOREACH(std::string skindir, mSearchSkinDirs) + for (const std::string& skindir : mSearchSkinDirs) { std::string subdir_path(add(skindir, subdir)); - BOOST_FOREACH(std::string subsubdir, subsubdirs) + for (const std::string& subsubdir : subsubdirs) { std::string full_path(add(subdir_path, subsubdir, filename)); @@ -908,7 +907,7 @@ std::vector LLDir::findSkinnedFilenames(const std::string& subdir, // current language, copy them -- in proper order -- into results. // Don't drive this by walking the map itself: it matters that we // generate results in the same order as subsubdirs. - BOOST_FOREACH(std::string subsubdir, subsubdirs) + for (const std::string& subsubdir : subsubdirs) { StringMap::const_iterator found(path_for.find(subsubdir)); if (found != path_for.end()) @@ -920,7 +919,7 @@ std::vector LLDir::findSkinnedFilenames(const std::string& subdir, LL_DEBUGS("LLDir") << empty; const char* comma = ""; - BOOST_FOREACH(std::string path, results) + for (const std::string& path : results) { LL_CONT << comma << "'" << path << "'"; comma = ", "; diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp index 3cff622a4b..60265cade6 100644 --- a/indra/llfilesystem/tests/lldir_test.cpp +++ b/indra/llfilesystem/tests/lldir_test.cpp @@ -34,7 +34,6 @@ #include "../test/lltut.h" #include "stringize.h" -#include #include using boost::assign::list_of; @@ -109,7 +108,7 @@ struct LLDir_Dummy: public LLDir "install/skins/default/future/somefile.txt" }; - BOOST_FOREACH(const char* path, preload) + for (const char* path : preload) { buildFilesystem(path); } @@ -166,7 +165,7 @@ struct LLDir_Dummy: public LLDir LLStringUtil::getTokens(path, components, "/"); // Ensure we have an entry representing every level of this path std::string partial; - BOOST_FOREACH(std::string component, components) + for (std::string component : components) { append(partial, component); mFilesystem.insert(partial); diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 95ae0856fe..9dc31845ea 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -2304,9 +2304,9 @@ bool LLImageFormatted::save(const std::string &filename) return false; } - outfile.write(getData(), getDataSize()); + S32 result = outfile.write(getData(), getDataSize()); outfile.close() ; - return true; + return (result != 0); } S8 LLImageFormatted::getCodec() const diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index c54a4699ba..64e368a152 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -48,7 +48,7 @@ std::string LLImageJ2C::getEngineInfo() { // All known LLImageJ2CImpl implementation subclasses are cheap to // construct. - boost::scoped_ptr impl(fallbackCreateLLImageJ2CImpl()); + std::unique_ptr impl(fallbackCreateLLImageJ2CImpl()); return impl->getEngineInfo(); } diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index e196f7479e..b30df6f776 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -95,7 +95,7 @@ protected: S8 mRawDiscardLevel; F32 mRate; bool mReversible; - boost::scoped_ptr mImpl; + std::unique_ptr mImpl; std::string mLastError; // Image compression/decompression tester diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 8b39d52b6a..ee33881839 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -32,6 +32,7 @@ #include "llinventorydefines.h" #include "llxorcipher.h" #include "llsd.h" +#include "llsdserialize.h" #include "message.h" #include @@ -217,7 +218,19 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream) } else if (0 == strcmp("metadata", keyword)) { - LLSD metadata(valuestr); + LLSD metadata; + if (strncmp("", valuestr, 6) == 0) + { + std::istringstream stream(valuestr); + LLSDSerialize::fromXML(metadata, stream); + } + else + { + // next line likely contains metadata, but at the moment is not supported + // can do something like: + // LLSDSerialize::fromNotation(metadata, input_stream, -1); + } + if (metadata.has("thumbnail")) { const LLSD& thumbnail = metadata["thumbnail"]; @@ -771,7 +784,19 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) } else if (0 == strcmp("metadata", keyword)) { - LLSD metadata(valuestr); + LLSD metadata; + if (strncmp("", valuestr, 6) == 0) + { + std::istringstream stream(valuestr); + LLSDSerialize::fromXML(metadata, stream); + } + else + { + // next line likely contains metadata, but at the moment is not supported + // can do something like: + // LLSDSerialize::fromNotation(metadata, input_stream, -1); + } + if (metadata.has("thumbnail")) { const LLSD& thumbnail = metadata["thumbnail"]; @@ -880,9 +905,14 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu if (mThumbnailUUID.notNull()) { + // Max length is 255 chars, will have to export differently if it gets more data + // Ex: use newline and toNotation (uses {}) for unlimited size LLSD metadata; metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); - output_stream << "\t\tmetadata\t" << metadata << "|\n"; + + output_stream << "\t\tmetadata\t"; + LLSDSerialize::toXML(metadata, output_stream); + output_stream << "|\n"; } // Check for permissions to see the asset id, and if so write it @@ -1381,7 +1411,19 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) } else if (0 == strcmp("metadata", keyword)) { - LLSD metadata(valuestr); + LLSD metadata; + if (strncmp("", valuestr, 6) == 0) + { + std::istringstream stream(valuestr); + LLSDSerialize::fromXML(metadata, stream); + } + else + { + // next line likely contains metadata, but at the moment is not supported + // can do something like: + // LLSDSerialize::fromNotation(metadata, input_stream, -1); + } + if (metadata.has("thumbnail")) { const LLSD& thumbnail = metadata["thumbnail"]; @@ -1421,9 +1463,12 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL) output_stream << "\t\tname\t" << mName.c_str() << "|\n"; if (mThumbnailUUID.notNull()) { + // Only up to 255 chars LLSD metadata; metadata["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID); - output_stream << "\t\tmetadata\t" << metadata << "|\n"; + output_stream << "\t\tmetadata\t"; + LLSDSerialize::toXML(metadata, output_stream); + output_stream << "|\n"; } output_stream << "\t}\n"; return TRUE; diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h index fae69c1e92..096310c017 100644 --- a/indra/llkdu/llimagej2ckdu.h +++ b/indra/llkdu/llimagej2ckdu.h @@ -116,10 +116,10 @@ private: }; // Encode variable - boost::scoped_ptr mInputp; + std::unique_ptr mInputp; CodeStreamHolder mCodeStreamp; - boost::scoped_ptr mTPosp; // tile position - boost::scoped_ptr mTileIndicesp; + std::unique_ptr mTPosp; // tile position + std::unique_ptr mTileIndicesp; int mBlocksSize; int mPrecinctsSize; int mLevels; @@ -128,7 +128,7 @@ private: // We don't own this LLImageRaw. We're simply pointing to an instance // passed into initDecode(). LLImageRaw *mRawImagep; - boost::scoped_ptr mDecodeState; + std::unique_ptr mDecodeState; }; #endif diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index e39397613b..69644e231e 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1003,7 +1003,7 @@ class LLVolume : public LLRefCount friend class LLVolumeLODGroup; protected: - ~LLVolume(); // use unref + virtual ~LLVolume(); // use unref public: typedef std::vector face_list_t; diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 2bf65cdf25..f261357c1d 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -95,7 +95,7 @@ public: private: struct QueuedCoproc { - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; QueuedCoproc(const std::string &name, const LLUUID &id, CoProcedure_t proc) : mName(name), @@ -115,7 +115,7 @@ private: // Use shared_ptr to control the lifespan of our CoprocQueue_t instance // because the consuming coroutine might outlive this LLCoprocedurePool // instance. - typedef boost::shared_ptr CoprocQueuePtr; + typedef std::shared_ptr CoprocQueuePtr; std::string mPoolName; size_t mPoolSize, mActiveCoprocsCount, mPending; @@ -301,7 +301,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): mPoolSize(size), mActiveCoprocsCount(0), mPending(0), - mPendingCoprocs(boost::make_shared(LLCoprocedureManager::DEFAULT_QUEUE_SIZE)), + mPendingCoprocs(std::make_shared(LLCoprocedureManager::DEFAULT_QUEUE_SIZE)), mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), mCoroMapping() { @@ -384,7 +384,7 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced LL_DEBUGS("CoProcMgr") << "Coprocedure(" << name << ") enqueuing with id=" << id.asString() << " in pool \"" << mPoolName << "\" at " << mPending << LL_ENDL; } - auto pushed = mPendingCoprocs->try_push(boost::make_shared(name, id, proc)); + auto pushed = mPendingCoprocs->try_push(std::make_shared(name, id, proc)); if (pushed == boost::fibers::channel_op_status::success) { ++mPending; diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index 6d0d68cf24..fc561c6b0f 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -263,8 +263,8 @@ class HttpCoroHandler : public LLCore::HttpHandler { public: - typedef boost::shared_ptr ptr_t; - typedef boost::weak_ptr wptr_t; + typedef std::shared_ptr ptr_t; + typedef std::weak_ptr wptr_t; HttpCoroHandler(LLEventStream &reply); @@ -317,8 +317,8 @@ public: static const std::string HTTP_RESULTS_CONTENT; static const std::string HTTP_RESULTS_RAW; - typedef boost::shared_ptr ptr_t; - typedef boost::weak_ptr wptr_t; + typedef std::shared_ptr ptr_t; + typedef std::weak_ptr wptr_t; HttpCoroutineAdapter(const std::string &name, LLCore::HttpRequest::policy_t policyId); ~HttpCoroutineAdapter(); diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 9f7768f78e..b7013dbb6e 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -298,6 +298,13 @@ BOOL LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char } htolememcpy(&size, mCurBufferp, MVT_S32, 4); + + if (size < 0) + { + LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData unpacked invalid size, aborting!" << LL_ENDL; + return FALSE; + } + mCurBufferp += 4; if (!verifyLength(size, name)) diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h index 8be4c64dfc..3ee45da2e7 100644 --- a/indra/llmessage/llexperiencecache.h +++ b/indra/llmessage/llexperiencecache.h @@ -112,7 +112,7 @@ private: // Callback types for get() typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t; - typedef boost::shared_ptr signal_ptr; + typedef std::shared_ptr signal_ptr; // May have multiple callbacks for a single ID, which are // represented as multiple slots bound to the signal. // Avoid copying signals via pointers. diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index c707c7ad09..e302dd2b5e 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -982,7 +982,7 @@ LLHTTPNode& LLIOHTTPServer::create( } LLHTTPResponseFactory* factory = new LLHTTPResponseFactory; - boost::shared_ptr factory_ptr(factory); + std::shared_ptr factory_ptr(factory); LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr); diff --git a/indra/llmessage/lliopipe.h b/indra/llmessage/lliopipe.h index 7fd4cee8ba..e6ac8ebfc2 100644 --- a/indra/llmessage/lliopipe.h +++ b/indra/llmessage/lliopipe.h @@ -89,7 +89,7 @@ public: /** * @brief Scattered memory container. */ - typedef boost::shared_ptr buffer_ptr_t; + typedef std::shared_ptr buffer_ptr_t; /** * @brief Enumeration for IO return codes diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index 303d80eb14..a62b3c0204 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -65,7 +65,7 @@ public: /** * @brief Reference counted shared pointers to sockets. */ - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; /** * @brief Type of socket to create. @@ -305,7 +305,7 @@ class LLIOServerSocket : public LLIOPipe { public: typedef LLSocket::ptr_t socket_t; - typedef boost::shared_ptr factory_t; + typedef std::shared_ptr factory_t; LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor); virtual ~LLIOServerSocket(); diff --git a/indra/llmessage/llservice.h b/indra/llmessage/llservice.h index 9c09aeb44c..f215acab56 100644 --- a/indra/llmessage/llservice.h +++ b/indra/llmessage/llservice.h @@ -116,7 +116,7 @@ class LLService : public LLIOPipe public: //typedef boost::intrusive_ptr creator_t; //typedef boost::intrusive_ptr service_t; - typedef boost::shared_ptr creator_t; + typedef std::shared_ptr creator_t; /** * @brief This method is used to register a protocol name with a diff --git a/indra/llmessage/llstoredmessage.h b/indra/llmessage/llstoredmessage.h index 9c98e2c558..6ea150fda3 100644 --- a/indra/llmessage/llstoredmessage.h +++ b/indra/llmessage/llstoredmessage.h @@ -46,7 +46,7 @@ private: std::string mName; }; -typedef boost::shared_ptr LLStoredMessagePtr; +typedef std::shared_ptr LLStoredMessagePtr; #endif // LL_STOREDMESSAGE_H diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp index b7fdf4f437..1c571a74da 100644 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ b/indra/llmessage/tests/llcurl_stub.cpp @@ -49,7 +49,7 @@ void LLCurl::Responder::httpCompleted() } void LLCurl::Responder::completedRaw(LLChannelDescriptors const&, - boost::shared_ptr const&) + std::shared_ptr const&) { } diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 8b50652386..f7acdd9866 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -335,7 +335,7 @@ public: // "init_history" message void initializeUrlHistory(const LLSD& url_history); - boost::shared_ptr getSharedPtr() { return boost::dynamic_pointer_cast(shared_from_this()); } // due to enable_shared_from_this + std::shared_ptr getSharedPtr() { return std::dynamic_pointer_cast(shared_from_this()); } // due to enable_shared_from_this protected: diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index b70dff86c3..b01ea359bf 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -43,7 +43,7 @@ #include "llsd.h" #include "llevents.h" -class LLPluginProcessParentOwner : public boost::enable_shared_from_this < LLPluginProcessParentOwner > +class LLPluginProcessParentOwner : public std::enable_shared_from_this < LLPluginProcessParentOwner > { public: virtual ~LLPluginProcessParentOwner(); @@ -60,7 +60,7 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner LLPluginProcessParent(LLPluginProcessParentOwner *owner); public: - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; ~LLPluginProcessParent(); diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 420a7e92aa..98646f4956 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -53,7 +53,6 @@ #pragma warning (default : 4264) #endif -#include #include #include "lldaeloader.h" @@ -958,7 +957,7 @@ LLDAELoader::LLDAELoader( mPreprocessDAE(preprocess) { // mesh loader suffix configuration - for(int i=0;i 0) { - index_string = "_" + boost::lexical_cast(ind); + index_string = "_" + std::to_string(ind); } // if parent has a name or ID, use it diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h index aeeabae549..5363f51912 100644 --- a/indra/llprimitive/lldaeloader.h +++ b/indra/llprimitive/lldaeloader.h @@ -28,6 +28,7 @@ #define LL_LLDAELOADER_H #include "llmodelloader.h" +#include // configurable lod suffixes class DAE; class daeElement; diff --git a/indra/llprimitive/llgltfloader.cpp b/indra/llprimitive/llgltfloader.cpp index 7394f99794..8e498158d6 100644 --- a/indra/llprimitive/llgltfloader.cpp +++ b/indra/llprimitive/llgltfloader.cpp @@ -48,8 +48,6 @@ // TODO: includes inherited from dae loader. Validate / prune -#include - #include "llsdserialize.h" #include "lljoint.h" diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index eae19a8f62..9510ceb2b3 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -71,6 +71,7 @@ LLModel::~LLModel() { LLConvexDecomposition::getInstance()->deleteDecomposition(mDecompID); } + mPhysics.mMesh.clear(); } //static diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 689172dda3..ff5280caa4 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -111,6 +111,8 @@ public: std::vector mPositions; std::vector mNormals; + ~PhysicsMesh() {} + void clear() { mPositions.clear(); @@ -136,6 +138,7 @@ public: public: Decomposition() { } Decomposition(LLSD& data); + ~Decomposition() { } void fromLLSD(LLSD& data); LLSD asLLSD() const; bool hasHullList() const; @@ -370,7 +373,7 @@ class LLModelInstanceBase { public: LLPointer mModel; - LLPointer mLOD[5]; + LLPointer mLOD[LLModel::NUM_LODS]; LLUUID mMeshID; LLMatrix4 mTransform; @@ -385,6 +388,15 @@ public: : mModel(NULL) { } + + virtual ~LLModelInstanceBase() + { + mModel = NULL; + for (int j = 0; j < LLModel::NUM_LODS; ++j) + { + mLOD[j] = NULL; + } + }; }; typedef std::vector model_instance_list; @@ -404,6 +416,8 @@ public: LLModelInstance(LLSD& data); + ~LLModelInstance() {} + LLSD asLLSD(); }; diff --git a/indra/llprimitive/tests/llmediaentry_test.cpp b/indra/llprimitive/tests/llmediaentry_test.cpp index b072ce3964..c3e17d1267 100644 --- a/indra/llprimitive/tests/llmediaentry_test.cpp +++ b/indra/llprimitive/tests/llmediaentry_test.cpp @@ -211,7 +211,7 @@ namespace tut void whitelist_test(int num, bool enable, const char *whitelist, const char *candidate_url, bool expected_pass) { - std::string message = "Whitelist test " + boost::lexical_cast(num); + std::string message = "Whitelist test " + std::to_string(num); LLMediaEntry entry; entry.setWhiteListEnable(enable); set_whitelist(entry, whitelist); diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp index b501cdfd77..28ccecfa35 100644 --- a/indra/llui/llcommandmanager.cpp +++ b/indra/llui/llcommandmanager.cpp @@ -34,8 +34,6 @@ #include "llerror.h" #include "llxuiparser.h" -#include - // // LLCommandId class @@ -186,7 +184,7 @@ bool LLCommandManager::load() return false; } - BOOST_FOREACH(LLCommand::Params& commandParams, commandsParams.commands) + for (const LLCommand::Params& commandParams : commandsParams.commands) { LLCommand * command = new LLCommand(commandParams); diff --git a/indra/llui/llfiltereditor.h b/indra/llui/llfiltereditor.h index 3a05bc05a1..52cad3bff4 100644 --- a/indra/llui/llfiltereditor.h +++ b/indra/llui/llfiltereditor.h @@ -43,6 +43,7 @@ class LLFilterEditor : public LLSearchEditor public: struct Params : public LLInitParam::Block {}; + virtual ~LLFilterEditor() {} protected: LLFilterEditor(const Params&); diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 1e38b7fceb..20e18d2055 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -59,7 +59,6 @@ #include "llmultifloater.h" #include "llsdutil.h" #include "lluiusage.h" -#include // use this to control "jumping" behavior when Ctrl-Tabbing @@ -1973,6 +1972,8 @@ void LLFloater::onClickTearOff(LLFloater* self) { if (self->mSaveRect) { + LLRect screen_rect = self->calcScreenRect(); + self->mPosition = LLCoordGL(screen_rect.getCenterX(), screen_rect.getCenterY()).convert(); self->storeRectControl(); } self->setMinimized(FALSE); // to reenable minimize button if it was minimized @@ -2684,7 +2685,7 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent) //{ // floaterp->translate(translate_x, translate_y); //} - BOOST_FOREACH(LLHandle dependent_floater, floaterp->mDependents) + for (LLHandle dependent_floater : floaterp->mDependents) { if (dependent_floater.get()) { @@ -2699,10 +2700,9 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent) void LLFloaterView::restoreAll() { // make sure all subwindows aren't minimized - child_list_t child_list = *(getChildList()); - for (child_list_const_iter_t child_it = child_list.begin(); child_it != child_list.end(); ++child_it) + for (auto child : *getChildList()) { - LLFloater* floaterp = dynamic_cast(*child_it); + LLFloater* floaterp = dynamic_cast(child); if (floaterp) { floaterp->setMinimized(FALSE); diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index fb24c08528..b73a173d00 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -453,8 +453,7 @@ void LLLayoutStack::updateLayout() : getRect().getHeight(); // first, assign minimum dimensions - LLLayoutPanel* panelp = NULL; - BOOST_FOREACH(panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -467,12 +466,15 @@ void LLLayoutStack::updateLayout() llassert(total_visible_fraction < 1.05f); // don't need spacing after last panel - space_to_distribute += panelp ? ll_round((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0; + if (!mPanels.empty()) + { + space_to_distribute += ll_round(F32(mPanelSpacing) * mPanels.back()->getVisibleAmount()); + } S32 remaining_space = space_to_distribute; if (space_to_distribute > 0 && total_visible_fraction > 0.f) { // give space proportionally to visible auto resize panels - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -485,7 +487,7 @@ void LLLayoutStack::updateLayout() } // distribute any left over pixels to non-collapsed, visible panels - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (remaining_space == 0) break; @@ -504,7 +506,7 @@ void LLLayoutStack::updateLayout() // Record new size for this panel mSavedSizes = LLSD(); // - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim); @@ -606,7 +608,7 @@ LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const { if (!panelp) return NULL; - BOOST_FOREACH(LLLayoutPanel* p, mPanels) + for (LLLayoutPanel* p : mPanels) { if (p == panelp) { @@ -620,7 +622,7 @@ LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) c { LLLayoutPanel* result = NULL; - BOOST_FOREACH(LLLayoutPanel* p, mPanels) + for (LLLayoutPanel* p : mPanels) { if (p->getName() == name) { @@ -634,7 +636,7 @@ LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) c void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp) { - BOOST_FOREACH(LLLayoutPanel* lp, mPanels) + for (LLLayoutPanel* lp : mPanels) { if (lp->mResizeBar == NULL) { @@ -737,7 +739,7 @@ void LLLayoutStack::updateFractionalSizes() { F32 total_resizable_dim = 0.f; - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -745,7 +747,7 @@ void LLLayoutStack::updateFractionalSizes() } } - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -766,7 +768,7 @@ void LLLayoutStack::normalizeFractionalSizes() S32 num_auto_resize_panels = 0; F32 total_fractional_size = 0.f; - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -777,7 +779,7 @@ void LLLayoutStack::normalizeFractionalSizes() if (total_fractional_size == 0.f) { // equal distribution - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -787,7 +789,7 @@ void LLLayoutStack::normalizeFractionalSizes() } else { // renormalize - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -804,7 +806,7 @@ bool LLLayoutStack::animatePanels() // // animate visibility // - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->getVisible()) { @@ -902,7 +904,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& LLLayoutPanel* other_resize_panel = NULL; LLLayoutPanel* following_panel = NULL; - BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels) + BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels) // Should replace this when C++20 reverse view adaptor becomes available... { if (panelp->mAutoResize) { @@ -951,7 +953,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& AFTER_RESIZED_PANEL } which_panel = BEFORE_RESIZED_PANEL; - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (!panelp->getVisible() || panelp->mCollapsed) { @@ -1042,6 +1044,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE); } + break; default: break; } @@ -1058,8 +1061,8 @@ void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent) void LLLayoutStack::updateResizeBarLimits() { - LLLayoutPanel* previous_visible_panelp = NULL; - BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels) + LLLayoutPanel* previous_visible_panelp{ nullptr }; + BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels) // Should replace this when C++20 reverse view adaptor becomes available... { if (!visible_panelp->getVisible() || visible_panelp->mCollapsed) { diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp index 1ede5b706f..e8b6b7e43b 100644 --- a/indra/llui/llloadingindicator.cpp +++ b/indra/llui/llloadingindicator.cpp @@ -34,7 +34,6 @@ // Project includes #include "lluictrlfactory.h" #include "lluiimage.h" -#include "boost/foreach.hpp" // registered in llui.cpp to avoid being left out by MS linker //static LLDefaultChildRegistry::Register r("loading_indicator"); @@ -52,7 +51,7 @@ LLLoadingIndicator::LLLoadingIndicator(const Params& p) void LLLoadingIndicator::initFromParams(const Params& p) { - BOOST_FOREACH(LLUIImage* image, p.images().image) + for (LLUIImage* image : p.images().image) { mImages.push_back(image); } diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 59a2d4e882..ff80675751 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -60,7 +60,6 @@ #include "v2math.h" #include #include -#include #include "llclipboard.h" // buildDrawLabel(); diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 5bc7d72b92..816356b2e2 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -45,7 +45,6 @@ #include #include -#include const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; @@ -446,14 +445,14 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par mSoundName = p.sound; } - BOOST_FOREACH(const LLNotificationTemplate::UniquenessContext& context, p.unique.contexts) + for (const LLNotificationTemplate::UniquenessContext& context : p.unique.contexts) { mUniqueContext.push_back(context.value); } LL_DEBUGS("Notifications") << "notification \"" << mName << "\": tag count is " << p.tags.size() << LL_ENDL; - BOOST_FOREACH(const LLNotificationTemplate::Tag& tag, p.tags) + for (const LLNotificationTemplate::Tag& tag : p.tags) { LL_DEBUGS("Notifications") << " tag \"" << std::string(tag.value) << "\"" << LL_ENDL; mTags.push_back(tag.value); @@ -1003,6 +1002,7 @@ LLBoundListener LLNotificationChannelBase::connectChangedImpl(const LLEventListe // all of the notifications that are already in the channel // we use a special signal called "load" in case the channel wants to care // only about new notifications + LLMutexLock lock(&mItemsMutex); for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) { slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); @@ -1162,7 +1162,7 @@ LLNotificationChannel::LLNotificationChannel(const Params& p) LLInstanceTracker(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()), mName(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()) { - BOOST_FOREACH(const std::string& source, p.sources) + for (const std::string& source : p.sources) { connectToChannel(source); } @@ -1180,6 +1180,14 @@ LLNotificationChannel::LLNotificationChannel(const std::string& name, connectToChannel(parent); } +LLNotificationChannel::~LLNotificationChannel() +{ + for (LLBoundListener &listener : mListeners) + { + listener.disconnect(); + } +} + bool LLNotificationChannel::isEmpty() const { return mItems.empty(); @@ -1187,17 +1195,7 @@ bool LLNotificationChannel::isEmpty() const S32 LLNotificationChannel::size() const { - return mItems.size(); -} - -LLNotificationChannel::Iterator LLNotificationChannel::begin() -{ - return mItems.begin(); -} - -LLNotificationChannel::Iterator LLNotificationChannel::end() -{ - return mItems.end(); + return mItems.size(); } size_t LLNotificationChannel::size() @@ -1205,12 +1203,19 @@ size_t LLNotificationChannel::size() return mItems.size(); } +void LLNotificationChannel::forEachNotification(NotificationProcess process) +{ + LLMutexLock lock(&mItemsMutex); + std::for_each(mItems.begin(), mItems.end(), process); +} + std::string LLNotificationChannel::summarize() { std::string s("Channel '"); s += mName; s += "'\n "; - for (LLNotificationChannel::Iterator it = begin(); it != end(); ++it) + LLMutexLock lock(&mItemsMutex); + for (LLNotificationChannel::Iterator it = mItems.begin(); it != mItems.end(); ++it) { s += (*it)->summarize(); s += "\n "; @@ -1222,14 +1227,14 @@ void LLNotificationChannel::connectToChannel( const std::string& channel_name ) { if (channel_name.empty()) { - LLNotifications::instance().connectChanged( - boost::bind(&LLNotificationChannelBase::updateItem, this, _1)); + mListeners.push_back(LLNotifications::instance().connectChanged( + boost::bind(&LLNotificationChannelBase::updateItem, this, _1))); } else { mParents.push_back(channel_name); LLNotificationChannelPtr p = LLNotifications::instance().getChannel(channel_name); - p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1)); + mListeners.push_back(p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1))); } } @@ -1531,7 +1536,7 @@ void replaceFormText(LLNotificationForm::Params& form, const std::string& patter form.ignore.text = replace; } - BOOST_FOREACH(LLNotificationForm::FormElement& element, form.form_elements.elements) + for (LLNotificationForm::FormElement& element : form.form_elements.elements) { if (element.button.isChosen() && element.button.text() == pattern) { @@ -1586,19 +1591,19 @@ bool LLNotifications::loadTemplates() mTemplates.clear(); - BOOST_FOREACH(LLNotificationTemplate::GlobalString& string, params.strings) + for (const LLNotificationTemplate::GlobalString& string : params.strings) { mGlobalStrings[string.name] = string.value; } std::map form_templates; - BOOST_FOREACH(LLNotificationTemplate::Template& notification_template, params.templates) + for (const LLNotificationTemplate::Template& notification_template : params.templates) { form_templates[notification_template.name] = notification_template.form; } - BOOST_FOREACH(LLNotificationTemplate::Params& notification, params.notifications) + for (LLNotificationTemplate::Params& notification : params.notifications) { if (notification.form_ref.form_template.isChosen()) { @@ -1653,7 +1658,7 @@ bool LLNotifications::loadVisibilityRules() mVisibilityRules.clear(); - BOOST_FOREACH(LLNotificationVisibilityRule::Rule& rule, params.rules) + for (const LLNotificationVisibilityRule::Rule& rule : params.rules) { mVisibilityRules.push_back(LLNotificationVisibilityRulePtr(new LLNotificationVisibilityRule(rule))); } @@ -1746,6 +1751,7 @@ void LLNotifications::cancel(LLNotificationPtr pNotif) void LLNotifications::cancelByName(const std::string& name) { + LLMutexLock lock(&mItemsMutex); std::vector notifs_to_cancel; for (LLNotificationSet::iterator it=mItems.begin(), end_it = mItems.end(); it != end_it; @@ -1770,6 +1776,7 @@ void LLNotifications::cancelByName(const std::string& name) void LLNotifications::cancelByOwner(const LLUUID ownerId) { + LLMutexLock lock(&mItemsMutex); std::vector notifs_to_cancel; for (LLNotificationSet::iterator it = mItems.begin(), end_it = mItems.end(); it != end_it; @@ -1817,11 +1824,6 @@ LLNotificationPtr LLNotifications::find(LLUUID uuid) } } -void LLNotifications::forEachNotification(NotificationProcess process) -{ - std::for_each(mItems.begin(), mItems.end(), process); -} - std::string LLNotifications::getGlobalString(const std::string& key) const { GlobalStringMap::const_iterator it = mGlobalStrings.find(key); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 824b03ad84..f38ecb6c85 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -745,16 +745,19 @@ class LLNotificationChannelBase : { LOG_CLASS(LLNotificationChannelBase); public: - LLNotificationChannelBase(LLNotificationFilter filter) - : mFilter(filter), - mItems() - {} + LLNotificationChannelBase(LLNotificationFilter filter) + : mFilter(filter) + , mItems() + , mItemsMutex() + {} + virtual ~LLNotificationChannelBase() { // explicit cleanup for easier issue detection mChanged.disconnect_all_slots(); mPassedFilter.disconnect_all_slots(); mFailedFilter.disconnect_all_slots(); + LLMutexLock lock(&mItemsMutex); mItems.clear(); } // you can also connect to a Channel, so you can be notified of @@ -793,6 +796,7 @@ protected: LLStandardSignal mChanged; LLStandardSignal mPassedFilter; LLStandardSignal mFailedFilter; + LLMutex mItemsMutex; // these are action methods that subclasses can override to take action // on specific types of changes; the management of the mItems list is @@ -842,7 +846,7 @@ public: LLNotificationChannel(const Params& p = Params()); LLNotificationChannel(const std::string& name, const std::string& parent, LLNotificationFilter filter); - virtual ~LLNotificationChannel() {} + virtual ~LLNotificationChannel(); typedef LLNotificationSet::iterator Iterator; std::string getName() const { return mName; } @@ -851,21 +855,23 @@ public: { return boost::iterator_range(mParents); } - - void connectToChannel(const std::string& channel_name); - + bool isEmpty() const; S32 size() const; - - Iterator begin(); - Iterator end(); - size_t size(); - + size_t size(); + + typedef boost::function NotificationProcess; + void forEachNotification(NotificationProcess process); + std::string summarize(); +protected: + void connectToChannel(const std::string& channel_name); + private: std::string mName; std::vector mParents; + std::vector mListeners; }; // An interface class to provide a clean linker seam to the LLNotifications class. @@ -931,10 +937,6 @@ public: void update(const LLNotificationPtr pNotif); LLNotificationPtr find(LLUUID uuid); - - typedef boost::function NotificationProcess; - - void forEachNotification(NotificationProcess process); // This is all stuff for managing the templates // take your template out @@ -998,7 +1000,7 @@ private: bool mIgnoreAllNotifications; // Disable test API - //boost::scoped_ptr mListener; + //std::unique_ptr mListener; std::vector mDefaultChannels; }; diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp index e73ba1fbe9..859222f907 100644 --- a/indra/llui/llnotificationslistener.cpp +++ b/indra/llui/llnotificationslistener.cpp @@ -32,7 +32,6 @@ #include "llnotificationtemplate.h" #include "llsd.h" #include "llui.h" -#include LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) : LLEventAPI("LLNotifications", @@ -149,11 +148,11 @@ void LLNotificationsListener::listChannelNotifications(const LLSD& params) const if (channel) { LLSD notifications(LLSD::emptyArray()); - for (LLNotificationChannel::Iterator ni(channel->begin()), nend(channel->end()); - ni != nend; ++ni) - { - notifications.append(asLLSD(*ni)); - } + std::function func = [notifications](LLNotificationPtr ni) mutable + { + notifications.append(asLLSD(ni)); + }; + channel->forEachNotification(func); response["notifications"] = notifications; } LLEventPumps::instance().obtain(params["reply"]).post(response); diff --git a/indra/llui/llsearcheditor.cpp b/indra/llui/llsearcheditor.cpp index cfaf08ec0a..8bf135f10c 100644 --- a/indra/llui/llsearcheditor.cpp +++ b/indra/llui/llsearcheditor.cpp @@ -104,6 +104,14 @@ LLSearchEditor::LLSearchEditor(const LLSearchEditor::Params& p) } } +LLSearchEditor::~LLSearchEditor() +{ + mSearchButton = NULL; + mClearButton = NULL; + mSearchEditor->deleteAllChildren(); + deleteAllChildren(); +} + //virtual void LLSearchEditor::draw() { diff --git a/indra/llui/llsearcheditor.h b/indra/llui/llsearcheditor.h index c0f3c1d60c..bd51988d07 100644 --- a/indra/llui/llsearcheditor.h +++ b/indra/llui/llsearcheditor.h @@ -74,7 +74,7 @@ protected: friend class LLUICtrlFactory; public: - virtual ~LLSearchEditor() {} + virtual ~LLSearchEditor(); /*virtual*/ void draw(); diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index cad13212f9..a0a09f9ce2 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -27,7 +27,6 @@ #include "linden_common.h" -#include #include "lltoolbar.h" #include "llcommandmanager.h" @@ -282,7 +281,7 @@ void LLToolBar::initFromParams(const LLToolBar::Params& p) mCenteringStack->addChild(mEndCenteringPanel); // - BOOST_FOREACH(LLCommandId id, p.commands) + for (const auto& id : p.commands) { addCommand(id); } @@ -480,7 +479,7 @@ BOOL LLToolBar::handleRightMouseDown(S32 x, S32 y, MASK mask) // Determine which button the mouse was over during the click in case the context menu action // is intended to affect the button. mRightMouseTargetButton = NULL; - BOOST_FOREACH(LLToolBarButton* button, mButtons) + for (LLToolBarButton* button : mButtons) { LLRect button_rect; button->localRectToOtherView(button->getLocalRect(), &button_rect, this); @@ -580,7 +579,7 @@ void LLToolBar::setButtonType(LLToolBarEnums::ButtonType button_type) void LLToolBar::resizeButtonsInRow(std::vector& buttons_in_row, S32 max_row_girth) { // make buttons in current row all same girth - BOOST_FOREACH(LLToolBarButton* button, buttons_in_row) + for (LLToolBarButton* button : buttons_in_row) { if (getOrientation(mSideType) == LLLayoutStack::HORIZONTAL) { @@ -781,7 +780,7 @@ void LLToolBar::updateLayoutAsNeeded() } else if (mLayoutStyle == LAYOUT_STYLE_EQUALIZE) { - BOOST_FOREACH(LLToolBarButton* button, mButtons) + for (LLToolBarButton* button : mButtons) { S32 width = button->getInitialWidth(); if (width > equalized_width) @@ -799,7 +798,7 @@ void LLToolBar::updateLayoutAsNeeded() } // - BOOST_FOREACH(LLToolBarButton* button, mButtons) + for (LLToolBarButton* button : mButtons) { // Add equalized and fill layout options // button->reshape(button->mWidthRange.getMin(), button->mDesiredHeight); @@ -1054,7 +1053,7 @@ void LLToolBar::createButtons() { std::set set_flashing; - BOOST_FOREACH(LLToolBarButton* button, mButtons) + for (LLToolBarButton* button : mButtons) { if (button->getFlashTimer() && button->getFlashTimer()->isFlashingInProgress()) { @@ -1072,7 +1071,7 @@ void LLToolBar::createButtons() mButtonMap.clear(); mRightMouseTargetButton = NULL; - BOOST_FOREACH(LLCommandId& command_id, mButtonCommands) + for (const LLCommandId& command_id : mButtonCommands) { LLToolBarButton* button = createButton(command_id); mButtons.push_back(button); diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 62371a9208..9e72e64013 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -444,7 +444,13 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params) tooltip_params.rect = LLRect (0, 1, 1, 0); if (tooltip_params.create_callback.isProvided()) - mToolTip = tooltip_params.create_callback()(tooltip_params); + { + mToolTip = tooltip_params.create_callback()(tooltip_params); + if (mToolTip == NULL) + { + return; + } + } else mToolTip = LLUICtrlFactory::create (tooltip_params); @@ -496,7 +502,7 @@ void LLToolTipMgr::show(const LLToolTip::Params& params) { if (!params.styled_message.isProvided() && (!params.message.isProvided() || params.message().empty()) - && !params.image.isProvided()) return; + && !params.image.isProvided() && !params.create_callback.isProvided()) return; // fill in default tooltip params from tool_tip.xml LLToolTip::Params params_with_defaults(params); params_with_defaults.fillFrom(LLUICtrlFactory::instance().getDefaultParams()); diff --git a/indra/llui/lluicolortable.cpp b/indra/llui/lluicolortable.cpp index 20051b330c..984d106f0e 100644 --- a/indra/llui/lluicolortable.cpp +++ b/indra/llui/lluicolortable.cpp @@ -32,7 +32,6 @@ #include "llui.h" #include "lluicolortable.h" #include "lluictrlfactory.h" -#include LLUIColorTable::ColorParams::ColorParams() : value("value"), @@ -234,7 +233,7 @@ bool LLUIColorTable::loadFromSettings() // pass constraint=LLDir::ALL_SKINS because we want colors.xml from every // skin dir - BOOST_FOREACH(std::string colors_path, + for (const std::string& colors_path : gDirUtilp->findSkinnedFilenames(LLDir::SKINBASE, "colors.xml", LLDir::ALL_SKINS)) { result |= loadFromFilename(colors_path, mLoadedColors); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 85ae38a6cb..5b457fe89d 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -32,7 +32,6 @@ #include #include -#include #include #include "llrender.h" @@ -66,6 +65,7 @@ static const S32 LINE_HEIGHT = 15; S32 LLView::sDepth = 0; bool LLView::sDebugRects = false; bool LLView::sDebugUnicode = false; +bool LLView::sDebugCamera = false; bool LLView::sIsRectDirty = false; LLRect LLView::sDirtyRect; bool LLView::sDebugRectsShowNames = true; @@ -643,7 +643,7 @@ void LLView::deleteAllChildren() void LLView::setAllChildrenEnabled(BOOL b) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { viewp->setEnabled(b); } @@ -672,7 +672,7 @@ void LLView::onVisibilityChange ( BOOL new_visibility ) { BOOL old_visibility; BOOL log_visibility_change = LLViewerEventRecorder::instance().getLoggingStatus(); - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { if (!viewp) { @@ -776,7 +776,7 @@ LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& m { if ( getVisible() && getEnabled() ) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { if ((viewp->*method)(c, mask, TRUE)) { @@ -795,7 +795,7 @@ LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& m template LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra, bool allow_mouse_block) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -824,7 +824,7 @@ LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDA LLView* LLView::childrenHandleToolTip(S32 x, S32 y, MASK mask) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -856,7 +856,7 @@ LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, // default to not accepting drag and drop, will be overridden by handler *accept = ACCEPT_NO; - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -882,7 +882,7 @@ LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -910,7 +910,7 @@ LLView* LLView::childFromPoint(S32 x, S32 y, bool recur) if (!getVisible()) return NULL; - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -1480,7 +1480,7 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent) mRect.mTop = getRect().mBottom + height; // move child views according to reshape flags - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { if (viewp != NULL) { @@ -1552,7 +1552,7 @@ LLRect LLView::calcBoundingRect() { LLRect local_bounding_rect = LLRect::null; - BOOST_FOREACH(LLView* childp, mChildList) + for (LLView* childp : mChildList) { // ignore invisible and "top" children when calculating bounding rect // such as combobox popups @@ -1715,7 +1715,7 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // Look for direct children *first* - BOOST_FOREACH(LLView* childp, mChildList) + for (LLView* childp : mChildList) { llassert(childp); if (childp->getName() == name) @@ -1726,7 +1726,7 @@ LLView* LLView::findChildView(const std::string& name, BOOL recurse) const if (recurse) { // Look inside each child as well. - BOOST_FOREACH(LLView* childp, mChildList) + for (LLView* childp : mChildList) { llassert(childp); LLView* viewp = childp->findChildView(name, recurse); @@ -2910,7 +2910,7 @@ S32 LLView::notifyParent(const LLSD& info) bool LLView::notifyChildren(const LLSD& info) { bool ret = false; - BOOST_FOREACH(LLView* childp, mChildList) + for (LLView* childp : mChildList) { ret = ret || childp->notifyChildren(info); } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 86893c2665..384b698606 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -672,6 +672,9 @@ public: // Show hexadecimal byte values of unicode symbols in a tooltip static bool sDebugUnicode; + // Show camera position and direction in Camera Controls floater + static bool sDebugCamera; + static bool sIsRectDirty; static LLRect sDirtyRect; diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index c0614811e7..78f980e7d6 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -65,13 +65,12 @@ HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam) { HRESULT hr; bool bGotMemory = false; - HRESULT hrCoInitialize = S_OK; IWbemLocator* pIWbemLocator = nullptr; IWbemServices* pIWbemServices = nullptr; BSTR pNamespace = nullptr; *pdwAdapterRam = 0; - hrCoInitialize = CoInitialize( 0 ); + CoInitializeEx(0, COINIT_APARTMENTTHREADED); hr = CoCreateInstance( CLSID_WbemLocator, nullptr, @@ -208,8 +207,7 @@ HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam) SAFE_RELEASE( pIWbemLocator ); - if( SUCCEEDED( hrCoInitialize ) ) - CoUninitialize(); + CoUninitialize(); if( bGotMemory ) return S_OK; @@ -232,9 +230,8 @@ S32 LLDXHardware::getMBVideoMemoryViaWMI() std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor) { std::string mDriverVersion; - HRESULT hrCoInitialize = S_OK; HRESULT hres; - hrCoInitialize = CoInitialize(0); + CoInitializeEx(0, COINIT_APARTMENTTHREADED); IWbemLocator *pLoc = NULL; hres = CoCreateInstance( @@ -437,10 +434,10 @@ std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor) { pEnumerator->Release(); } - if (SUCCEEDED(hrCoInitialize)) - { - CoUninitialize(); - } + + // supposed to always call CoUninitialize even if init returned false + CoUninitialize(); + return mDriverVersion; } @@ -690,7 +687,8 @@ BOOL LLDXHardware::getInfo(BOOL vram_only, bool disable_wmi) BOOL ok = FALSE; HRESULT hr; - CoInitialize(NULL); + // CLSID_DxDiagProvider does not work with Multithreaded? + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); IDxDiagProvider *dx_diag_providerp = NULL; IDxDiagContainer *dx_diag_rootp = NULL; @@ -986,7 +984,7 @@ LLSD LLDXHardware::getDisplayInfo() LLTimer hw_timer; HRESULT hr; LLSD ret; - CoInitialize(NULL); + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); IDxDiagProvider *dx_diag_providerp = NULL; IDxDiagContainer *dx_diag_rootp = NULL; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 4264a5b098..ad6219ed84 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -151,6 +151,7 @@ set(viewer_SOURCE_FILES fsnearbychatvoicemonitor.cpp fspanelblocklist.cpp fspanelcontactsets.cpp + fspanelface.cpp fspanelimcontrolpanel.cpp fspanellogin.cpp fspanelprefs.cpp @@ -343,6 +344,7 @@ set(viewer_SOURCE_FILES llfloaterimcontainer.cpp llfloaterinspect.cpp llfloaterinventorysettings.cpp + llfloaterinventorythumbnailshelper.cpp llfloaterjoystick.cpp llfloaterlagmeter.cpp llfloaterland.cpp @@ -942,6 +944,7 @@ set(viewer_HEADER_FILES fsnearbychatvoicemonitor.h fspanelblocklist.h fspanelcontactsets.h + fspanelface.h fspanelimcontrolpanel.h fspanellogin.h fspanelprefs.h @@ -1139,6 +1142,7 @@ set(viewer_HEADER_FILES llfloaterimcontainer.h llfloaterinspect.h llfloaterinventorysettings.h + llfloaterinventorythumbnailshelper.h llfloaterjoystick.h llfloaterlagmeter.h llfloaterland.h @@ -1977,50 +1981,14 @@ endif (WINDOWS) # Add the xui files. This is handy for searching for xui elements # from within the IDE. -# Make all XUI files accessible in Visual Studio -#set(viewer_XUI_FILES -# skins/default/colors.xml -# skins/default/default_languages.xml -# skins/default/textures/textures.xml -# ) -#file(GLOB DEFAULT_XUI_FILE_GLOB_LIST -# ${CMAKE_CURRENT_SOURCE_DIR}/skins/*/xui/en/*.xml) -#list(APPEND viewer_XUI_FILES ${DEFAULT_XUI_FILE_GLOB_LIST}) - -#file(GLOB DEFAULT_WIDGET_FILE_GLOB_LIST -# ${CMAKE_CURRENT_SOURCE_DIR}/skins/*/xui/en/widgets/*.xml) -#list(APPEND viewer_XUI_FILES ${DEFAULT_WIDGET_FILE_GLOB_LIST}) - -## Cannot append empty lists in CMake, wait until we have files here. -##file(GLOB SILVER_WIDGET_FILE_GLOB_LIST -## ${CMAKE_CURRENT_SOURCE_DIR}/skins/silver/xui/en-us/widgets/*.xml) -##list(APPEND viewer_XUI_FILES ${SILVER_WIDGET_FILE_GLOB_LIST}) - -#list(SORT viewer_XUI_FILES) - -#source_group("XUI Files" FILES ${viewer_XUI_FILES}) - -#set_source_files_properties(${viewer_XUI_FILES} -# PROPERTIES HEADER_FILE_ONLY TRUE) - -#list(APPEND viewer_SOURCE_FILES ${viewer_XUI_FILES}) - file(GLOB_RECURSE viewer_XUI_FILES LIST_DIRECTORIES FALSE ${CMAKE_CURRENT_SOURCE_DIR}/skins/*.xml) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/skins PREFIX "XUI Files" FILES ${viewer_XUI_FILES}) set_source_files_properties(${viewer_XUI_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND viewer_SOURCE_FILES ${viewer_XUI_FILES}) -# - -file(GLOB_RECURSE viewer_SHADER_FILES LIST_DIRECTORIES FALSE - ${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders/*.glsl) -source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders PREFIX "Shaders" FILES ${viewer_SHADER_FILES}) -set_source_files_properties(${viewer_SHADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) -list(APPEND viewer_SOURCE_FILES ${viewer_SHADER_FILES}) - +# Add the shader sources file(GLOB_RECURSE viewer_SHADER_FILES LIST_DIRECTORIES FALSE ${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders/*.glsl) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders PREFIX "Shaders" FILES ${viewer_SHADER_FILES}) @@ -2294,7 +2262,7 @@ if (WINDOWS) if (PACKAGE) add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2 + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py @@ -2339,7 +2307,7 @@ if (WINDOWS) ) # temporarily disable packaging of event_host until hg subrepos get # sorted out on the parabuild cluster... - #${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2) + #${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz) endif (PACKAGE) elseif (DARWIN) @@ -2491,7 +2459,7 @@ if (LINUX) add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer10 media_plugin_cef linux-crash-logger) add_custom_command( - OUTPUT ${product}.tar.bz2 + OUTPUT ${product}.tar.xz COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py @@ -2544,7 +2512,7 @@ if (LINUX) add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched) if (PACKAGE) - add_custom_target(llpackage ALL DEPENDS ${product}.tar.bz2) + add_custom_target(llpackage ALL DEPENDS ${product}.tar.xz) # Make sure we don't run two instances of viewer_manifest.py at the same time. add_dependencies(llpackage copy_l_viewer_manifest) check_message_template(llpackage) @@ -2693,7 +2661,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE # OUTPUT_VARIABLE PARENT_DIRECTORY_CYGWIN # OUTPUT_STRIP_TRAILING_WHITESPACE) # add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" - # # Use of 'tar ...j' here assumes VIEWER_SYMBOL_FILE endswith .tar.bz2; + # # Use of 'tar ...j' here assumes VIEWER_SYMBOL_FILE endswith .tar.xz; # # testing a string suffix is painful enough in CMake language that # # we'll continue assuming it until forced to generalize. # COMMAND "tar" diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 14627a7c8c..2380dcfd47 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.6 +7.1.7 diff --git a/indra/newview/app_settings/graphic_preset_controls.xml b/indra/newview/app_settings/graphic_preset_controls.xml index 87c653c43a..4cdf8e94c3 100644 --- a/indra/newview/app_settings/graphic_preset_controls.xml +++ b/indra/newview/app_settings/graphic_preset_controls.xml @@ -19,29 +19,55 @@ RenderAvatarMaxComplexity RenderAvatarMaxNonImpostors RenderAvatarPhysicsLODFactor + RenderCloudShadowAmbianceFactor RenderCompressTextures RenderDeferredSSAO RenderDepthOfField RenderDepthOfFieldInEditMode + RenderDisablePostProcessing + RenderPostProcessingHDR + RenderDefaultProbeUpdatePeriod RenderDynamicExposureCoefficient RenderExposure RenderFarClip RenderFlexTimeFactor RenderFSAASamples RenderGlow + RenderGlowHDR RenderGlowIterations + RenderGlowNoise RenderGlowResolutionPow RenderLocalLightCount RenderMaxPartCount + RenderMaxVRAMBudget RenderQualityPerformance RenderReflectionsEnabled + RenderReflectionProbeAmbiance RenderReflectionProbeDetail + RenderReflectionProbeDrawDistance RenderReflectionProbeLevel + RenderReflectionProbeMaxLocalLightAmbiance + RenderReflectionProbeResolution + RenderReflectionProbeVolumes RenderScreenSpaceReflections + RenderScreenSpaceReflectionIterations + RenderScreenSpaceReflectionRayStep + RenderScreenSpaceReflectionDistanceBias + RenderScreenSpaceReflectionDepthRejectBias + RenderScreenSpaceReflectionAdaptiveStepMultiplier + RenderScreenSpaceReflectionGlossySamples RenderShaderLightingMaxLevel RenderShadowDetail RenderShadowResolutionScale + RenderSkyAmbientScale + RenderSkyAutoAdjustAmbientScale + RenderSkyAutoAdjustBlueDensityScale + RenderSkyAutoAdjustBlueHorizonScale + RenderSkyAutoAdjustSunColorScale + RenderSkyAutoAdjustHDRScale RenderSkyAutoAdjustLegacy + RenderSkyAutoAdjustProbeAmbiance + RenderSkySunlightScale RenderSSAOIrradianceScale RenderSSAOIrradianceMax RenderSunDynamicRange diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b429032a28..55d0affbb1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12457,7 +12457,7 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1.0 - RendeSkyAutoAdjustBlueHorizonScale + RenderSkyAutoAdjustBlueHorizonScale Comment Blue Horizon Scale value to use when auto-adjusting legacy skies @@ -12468,7 +12468,7 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1.0 - RendeSkyAutoAdjustBlueDensityScale + RenderSkyAutoAdjustBlueDensityScale Comment Blue Horizon Scale value to use when auto-adjusting legacy skies @@ -16580,6 +16580,21 @@ Change of this parameter will affect the layout of buttons in notification toast Backup 0 + FSShowSelectedInBlinnPhong + + Comment + Show BlinnPhong while selected (non-persistent).This setting is driven by the code, not by user + Persist + 0 + Type + Boolean + Value + 0 + Backup + 0 + HideFromEditor + 1 + ShowSpecificLODInEdit Comment @@ -25045,5 +25060,57 @@ Change of this parameter will affect the layout of buttons in notification toast Value 128578 - + FSUseNewTexturePanel + + Backup + 1 + Comment + Use the new Texture/Material editor panel in build mode + Persist + 1 + Type + Boolean + Value + 1 + + FSInternalCanEditObjectFaces + + Comment + Internal control to show/hide object texture/material edit controls + HideFromEditor + 1 + Persist + 0 + Type + Boolean + Value + 1 + + FSInternalFaceHasBPNormalMap + + Comment + Internal control to store a flag about the edited face having a Blinn-Phong normal map or not + HideFromEditor + 1 + Persist + 0 + Type + Boolean + Value + 1 + + FSInternalFaceHasBPSpecularMap + + Comment + Internal control to store a flag about the edited face having a Blinn-Phong specular map or not + HideFromEditor + 1 + Persist + 0 + Type + Boolean + Value + 1 + + diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 243b17cf73..ed9a8240e4 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -2023,7 +2023,7 @@ value_min="-1" value_max="1"> - + - - @@ -2043,7 +2044,7 @@ name="mFaceEyeAltRight" scale="0 0 0" offset="-.005 0 0" /> - + - @@ -2063,17 +2064,17 @@ name="mFaceEyeLidUpperLeft" scale="0 0.3 0.7" offset=" 0 0 0" /> - + - + - + diff --git a/indra/newview/fspanelface.cpp b/indra/newview/fspanelface.cpp new file mode 100644 index 0000000000..8e714cc9c9 --- /dev/null +++ b/indra/newview/fspanelface.cpp @@ -0,0 +1,5982 @@ +/** + * @file fspanelface.cpp + * @brief Consolidated materials/texture panel in the tools floater + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2024, Zi Ree@Second Life + * + * 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 "fspanelface.h" + +#include // Used to find all faces with same texture + +#include "llagent.h" +#include "llagentdata.h" +#include "llbutton.h" +#include "llcalc.h" +#include "llcheckboxctrl.h" +#include "llcolorswatch.h" +#include "llcombobox.h" +#include "lldrawpoolbump.h" +#include "llerror.h" +#include "llface.h" +// #include "llfilesystem.h" +#include "llfetchedgltfmaterial.h" +#include "llgltfmateriallist.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" // gInventory +#include "llinventorymodelbackgroundfetch.h" +#include "llfloatermediasettings.h" +#include "llfloaterreg.h" +#include "llfloatertools.h" +#include "llfontgl.h" +#include "lllineeditor.h" +#include "llmaterialmgr.h" +#include "llmaterialeditor.h" +#include "llmediactrl.h" +#include "llmediaentry.h" +#include "llmenubutton.h" +#include "llnotificationsutil.h" +#include "llpanelcontents.h" +#include "llpluginclassmedia.h" +#include "llradiogroup.h" +#include "llrect.h" +#include "llresmgr.h" +// #include "llsd.h" +// #include "llsdserialize.h" +// #include "llsdutil.h" +#include "llselectmgr.h" +#include "llspinctrl.h" +#include "llstring.h" +#include "lltextbox.h" +#include "lltexturectrl.h" +#include "lltextureentry.h" +#include "lltooldraganddrop.h" +#include "lltoolface.h" +#include "lltoolmgr.h" +#include "lltrans.h" +#include "llui.h" +// #include "llviewerassetupload.h" +#include "llviewercontrol.h" +#include "llviewermedia.h" +// #include "llviewermenufile.h" +#include "llviewerobject.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llvovolume.h" +#include "llvoinventorylistener.h" +#include "lluictrlfactory.h" +#include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI + +// Dirty flags - taken from llmaterialeditor.cpp ... LL please put this in a .h! -Zi +static const U32 MATERIAL_BASE_COLOR_DIRTY = 0x1 << 0; +static const U32 MATERIAL_BASE_COLOR_TEX_DIRTY = 0x1 << 1; + +static const U32 MATERIAL_NORMAL_TEX_DIRTY = 0x1 << 2; + +static const U32 MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY = 0x1 << 3; +static const U32 MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY = 0x1 << 4; +static const U32 MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY = 0x1 << 5; + +static const U32 MATERIAL_EMISIVE_COLOR_DIRTY = 0x1 << 6; +static const U32 MATERIAL_EMISIVE_TEX_DIRTY = 0x1 << 7; + +static const U32 MATERIAL_DOUBLE_SIDED_DIRTY = 0x1 << 8; +static const U32 MATERIAL_ALPHA_MODE_DIRTY = 0x1 << 9; +static const U32 MATERIAL_ALPHA_CUTOFF_DIRTY = 0x1 << 10; + +FSPanelFace::Selection FSPanelFace::sMaterialOverrideSelection; + +void FSPanelFace::updateSelectedGLTFMaterials(std::function func) +{ + struct LLSelectedTEGLTFMaterialFunctor : public LLSelectedTEFunctor + { + LLSelectedTEGLTFMaterialFunctor(std::function func) : mFunc(func) {} + virtual ~LLSelectedTEGLTFMaterialFunctor() {}; + bool apply(LLViewerObject* object, S32 face) override + { + LLGLTFMaterial new_override; + const LLTextureEntry* tep = object->getTE(face); + if (tep->getGLTFMaterialOverride()) + { + new_override = *tep->getGLTFMaterialOverride(); + } + mFunc(&new_override); + LLGLTFMaterialList::queueModify(object, face, &new_override); + + return true; + } + + std::function mFunc; + } select_func(func); + + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func); +} + +template +void readSelectedGLTFMaterial(std::function func, T& value, bool& identical, bool has_tolerance, T tolerance) +{ + struct LLSelectedTEGetGLTFMaterialFunctor : public LLSelectedTEGetFunctor + { + LLSelectedTEGetGLTFMaterialFunctor(std::function func) : mFunc(func) {} + virtual ~LLSelectedTEGetGLTFMaterialFunctor() {}; + T get(LLViewerObject* object, S32 face) override + { + const LLTextureEntry* tep = object->getTE(face); + const LLGLTFMaterial* render_material = tep->getGLTFRenderMaterial(); + + return mFunc(render_material); + } + + std::function mFunc; + } select_func(func); + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&select_func, value, has_tolerance, tolerance); +} + +// +// keep LLRenderMaterialFunctor in sync with llmaterialeditor.cpp - Would be nice if we +// had this in its own file so we could include it from both sides ... -Zi +// + +// local preview of material changes +class LLRenderMaterialFunctor : public LLSelectedTEFunctor +{ +public: + LLRenderMaterialFunctor(const LLUUID &id) + : mMatId(id) + { + } + + bool apply(LLViewerObject* objectp, S32 te) override + { + if (objectp && objectp->permModify() && objectp->getVolume()) + { + LLVOVolume* vobjp = (LLVOVolume*)objectp; + vobjp->setRenderMaterialID(te, mMatId, false /*preview only*/); + vobjp->updateTEMaterialTextures(te); + } + return true; + } +private: + LLUUID mMatId; +}; + +// +// keep LLRenderMaterialOverrideFunctor in sync with llmaterialeditor.cpp just take +// out the reverting functionality as it makes no real sense with all the texture +// controls visible for the material at all times. +// TODO: look at how to handle local textures, especially when saving materials +// - Would be nice if we had this in its own file so we could include it from both sides ... -Zi +// +class LLRenderMaterialOverrideFunctor : public LLSelectedNodeFunctor +{ +public: + LLRenderMaterialOverrideFunctor( + LLGLTFMaterial* material_to_apply, + U32 unsaved_changes + ) + : mMaterialToApply(material_to_apply) + , mUnsavedChanges(unsaved_changes) + { + } + + virtual bool apply(LLSelectNode* nodep) override + { + LLViewerObject* objectp = nodep->getObject(); + if (!objectp || !objectp->permModify() || !objectp->getVolume()) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10001 << " skipped object" << LL_ENDL; + return false; + } + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); // avatars have TEs but no faces + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10002 << " " << num_tes << LL_ENDL; + + // post override from given object and te to the simulator + // requestData should have: + // object_id - UUID of LLViewerObject + // side - S32 index of texture entry + // gltf_json - String of GLTF json for override data + + for (S32 te = 0; te < num_tes; ++te) + { + if (!nodep->isTESelected(te)) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10003 << " skipping unselected te " << te << LL_ENDL; + continue; + } + + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10004 << " te " << te << LL_ENDL; + // Get material from object + // Selection can cover multiple objects, and live editor is + // supposed to overwrite changed values only + LLTextureEntry* tep = objectp->getTE(te); + + if (tep->getGLTFMaterial() == nullptr) + { + // overrides are not supposed to work or apply if + // there is no base material to work from + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10004 << " skipping te with no base material " << te << LL_ENDL; + continue; + } + + LLPointer material = tep->getGLTFMaterialOverride(); + LL_DEBUGS("APPLY_GLTF_CHANGES") << "10004b" << " material is null? " << material.isNull() << LL_ENDL; + // make a copy to not invalidate existing + // material for multiple objects + if (material.isNull()) + { + // Start with a material override which does not make any changes + material = new LLGLTFMaterial(); + } + else + { + material = new LLGLTFMaterial(*material); + } + + // Override object's values with values from editor where appropriate + if (mUnsavedChanges & MATERIAL_BASE_COLOR_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_BASE_COLOR_DIRTY" << LL_ENDL; + material->setBaseColorFactor(mMaterialToApply->mBaseColor, true); + } + + if (mUnsavedChanges & MATERIAL_BASE_COLOR_TEX_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_BASE_COLOR_TEX_DIRTY" << LL_ENDL; + material->setBaseColorId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR], true); + /* + LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_BASE_COLOR_TEX_DIRTY); + if (tracking_id.notNull()) + { + LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material); + } + */ + } + + if (mUnsavedChanges & MATERIAL_NORMAL_TEX_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_NORMAL_TEX_DIRTY" << LL_ENDL; + material->setNormalId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL], true); + /* + LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_NORMAL_TEX_DIRTY); + if (tracking_id.notNull()) + { + LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material); + } + */ + } + + if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY" << LL_ENDL; + material->setOcclusionRoughnessMetallicId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS], true); + /* + LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY); + if (tracking_id.notNull()) + { + LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material); + } + */ + } + + if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY" << LL_ENDL; + material->setMetallicFactor(mMaterialToApply->mMetallicFactor, true); + } + + if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY" << LL_ENDL; + material->setRoughnessFactor(mMaterialToApply->mRoughnessFactor, true); + } + + if (mUnsavedChanges & MATERIAL_EMISIVE_COLOR_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_EMISIVE_COLOR_DIRTY" << LL_ENDL; + material->setEmissiveColorFactor(LLColor3(mMaterialToApply->mEmissiveColor), true); + } + + if (mUnsavedChanges & MATERIAL_EMISIVE_TEX_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_EMISIVE_TEX_DIRTY" << LL_ENDL; + material->setEmissiveId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE], true); + /* + LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_EMISIVE_TEX_DIRTY); + if (tracking_id.notNull()) + { + LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material); + } + */ + } + + if (mUnsavedChanges & MATERIAL_DOUBLE_SIDED_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_DOUBLE_SIDED_DIRTY" << LL_ENDL; + material->setDoubleSided(mMaterialToApply->mDoubleSided, true); + } + + if (mUnsavedChanges & MATERIAL_ALPHA_MODE_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_ALPHA_MODE_DIRTY" << LL_ENDL; + material->setAlphaMode(mMaterialToApply->mAlphaMode, true); + } + + if (mUnsavedChanges & MATERIAL_ALPHA_CUTOFF_DIRTY) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_ALPHA_CUTOFF_DIRTY" << LL_ENDL; + material->setAlphaCutoff(mMaterialToApply->mAlphaCutoff, true); + } + + LL_DEBUGS("APPLY_GLTF_CHANGES") << 10100 << " queueing material update " << te << LL_ENDL; + LLGLTFMaterialList::queueModify(objectp, te, material); + } + return true; + } + +private: + LLGLTFMaterial* mMaterialToApply; + U32 mUnsavedChanges; +}; + +// +// Get all material parameters +// +struct LLSelectedTEGetmatId : public LLSelectedTEFunctor +{ + LLSelectedTEGetmatId() : + mHasFacesWithoutPBR(false), + mHasFacesWithPBR(false), + mInitialized(false), + mMaterial(nullptr) + { + } + + bool apply(LLViewerObject* object, S32 te_index) override + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "object " << object << " te_index " << te_index << LL_ENDL; + LLUUID pbr_id = object->getRenderMaterialID(te_index); + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000000 << " Material: " << pbr_id << LL_ENDL; + + if (pbr_id.isNull()) + { + mHasFacesWithoutPBR = true; + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000001 << LL_ENDL; + return false; + } + + mHasFacesWithPBR = true; + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000002 << LL_ENDL; + + if (mInitialized) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000003 << LL_ENDL; + if (mMaterialId != pbr_id) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000004 << LL_ENDL; + mIdenticalMaterial = false; + } + + LLGLTFMaterial* te_mat = object->getTE(te_index)->getGLTFMaterial(); + LLGLTFMaterial* te_override = object->getTE(te_index)->getGLTFMaterialOverride(); + + // copy base material values to the override material, so we can apply the override to it in the next steps + if (te_mat) + { + mMaterialOverride = *te_mat; + } + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000005 << " te_override:" << te_override << LL_ENDL; + for(U32 map = 0; map < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; map++) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000009 << " map:" << map << LL_ENDL; + + LLUUID texture_map_id; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000018 << "te_mat:" << te_mat << " mMaterialOverride.mTextureId[map]:" << mMaterialOverride.mTextureId[map] << LL_ENDL; + texture_map_id = mMaterialOverride.mTextureId[map]; + + if (te_override) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000018b" << " te_override->mTextureId[map]:" << te_override->mTextureId[map] << LL_ENDL; + if (te_override->mTextureId[map].notNull()) + { + texture_map_id = te_override->mTextureId[map]; + if (texture_map_id == LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID) + { + texture_map_id.setNull(); + } + } + } + + if (texture_map_id != mMaterialSummary.mTextureId[map]) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000018 << " mIdenticalMap[" << map << "]: false" << LL_ENDL; + mIdenticalMap[map] = false; + } + } + + if (te_override) + { + // copy values from base material to the override where the override has defaults + if (te_override->mBaseColor == LLGLTFMaterial::getDefaultBaseColor()) mMaterialOverride.mBaseColor = te_mat->mBaseColor; + if (te_override->mMetallicFactor == LLGLTFMaterial::getDefaultMetallicFactor()) mMaterialOverride.mMetallicFactor = te_mat->mMetallicFactor; + if (te_override->mRoughnessFactor == LLGLTFMaterial::getDefaultRoughnessFactor()) mMaterialOverride.mRoughnessFactor = te_mat->mRoughnessFactor; + if (te_override->mEmissiveColor == LLGLTFMaterial::getDefaultEmissiveColor()) mMaterialOverride.mEmissiveColor = te_mat->mEmissiveColor; + if (te_override->mDoubleSided == LLGLTFMaterial::getDefaultDoubleSided()) mMaterialOverride.mDoubleSided = te_mat->mDoubleSided; + if (te_override->mAlphaMode == LLGLTFMaterial::getDefaultAlphaMode()) mMaterialOverride.mAlphaMode = te_mat->mAlphaMode; + if (te_override->mAlphaCutoff == LLGLTFMaterial::getDefaultAlphaCutoff()) mMaterialOverride.mAlphaCutoff = te_mat->mAlphaCutoff; + } + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000018c" << " te_mat->mEmissiveColor:" << te_mat->mEmissiveColor << LL_ENDL; + + if (mMaterialOverride.mBaseColor != mMaterialSummary.mBaseColor) mIdenticalBaseColor = false; + if (mMaterialOverride.mMetallicFactor != mMaterialSummary.mMetallicFactor) mIdenticalMetallic = false; + if (mMaterialOverride.mRoughnessFactor != mMaterialSummary.mRoughnessFactor) mIdenticalRoughness = false; + if (mMaterialOverride.mEmissiveColor != mMaterialSummary.mEmissiveColor) mIdenticalEmissive = false; + if (mMaterialOverride.mDoubleSided != mMaterialSummary.mDoubleSided) mIdenticalDoubleSided = false; + if (mMaterialOverride.mAlphaMode != mMaterialSummary.mAlphaMode) mIdenticalAlphaMode = false; + if (mMaterialOverride.mAlphaCutoff != mMaterialSummary.mAlphaCutoff) mIdenticalAlphaCutoff = false; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000011 << LL_ENDL; + } + else + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000012 << LL_ENDL; + + mIdenticalMaterial = true; + mIdenticalBaseColor = true; + mIdenticalMetallic = true; + mIdenticalRoughness = true; + mIdenticalEmissive = true; + mIdenticalDoubleSided = true; + mIdenticalAlphaMode = true; + mIdenticalAlphaCutoff = true; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000013 << LL_ENDL; + + LLGLTFMaterial* mat = object->getTE(te_index)->getGLTFMaterial(); + LLGLTFMaterial* override = object->getTE(te_index)->getGLTFMaterialOverride(); + + mMaterialId = pbr_id; + mMaterial = override; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000014 << " override:" << override << LL_ENDL; + + // copy base material values to the "summary" material, so we can apply the override to it in the next step + if (mat) + { + mMaterialSummary = *mat; + } + + for(U32 map = 0; map < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; map++) + { + // initialize array to say "all PBR maps are the same" + mIdenticalMap[map] = true; + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000017 << " map:" << map << LL_ENDL; + + if (override && override->mTextureId[map].notNull()) + { + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000017b" << " override->mTextureId[map]:" << override->mTextureId[map] << LL_ENDL; + if (override->mTextureId[map] == LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID) + { + mMaterialSummary.mTextureId[map].setNull(); + } + else + { + mMaterialSummary.mTextureId[map] = override->mTextureId[map]; + } + } + } + + if (override) + { + // copy values from override to the "summary" material where the override differs from the default + if (override->mBaseColor != LLGLTFMaterial::getDefaultBaseColor()) mMaterialSummary.mBaseColor = override->mBaseColor; + if (override->mMetallicFactor != LLGLTFMaterial::getDefaultMetallicFactor()) mMaterialSummary.mMetallicFactor = override->mMetallicFactor; + if (override->mRoughnessFactor != LLGLTFMaterial::getDefaultRoughnessFactor()) mMaterialSummary.mRoughnessFactor = override->mRoughnessFactor; + if (override->mEmissiveColor != LLGLTFMaterial::getDefaultEmissiveColor()) mMaterialSummary.mEmissiveColor = override->mEmissiveColor; + if (override->mDoubleSided != LLGLTFMaterial::getDefaultDoubleSided()) mMaterialSummary.mDoubleSided = override->mDoubleSided; + if (override->mAlphaMode != LLGLTFMaterial::getDefaultAlphaMode()) mMaterialSummary.setAlphaMode(override->getAlphaMode()); + if (override->mAlphaCutoff != LLGLTFMaterial::getDefaultAlphaCutoff()) mMaterialSummary.mAlphaCutoff = override->mAlphaCutoff; + } + + mInitialized = true; + } + + return true; + } + + bool mHasFacesWithoutPBR; + bool mHasFacesWithPBR; + bool mInitialized; + + LLGLTFMaterial* mMaterial; + LLGLTFMaterial mMaterialOverride; + LLGLTFMaterial mMaterialSummary; + + bool mIdenticalMaterial; + + bool mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT]; + bool mIdenticalBaseColor; + bool mIdenticalMetallic; + bool mIdenticalRoughness; + bool mIdenticalEmissive; + bool mIdenticalDoubleSided; + bool mIdenticalAlphaMode; + bool mIdenticalAlphaCutoff; + + LLUUID mMaterialId; +}; + +// +// "Use texture" label for normal/specular type comboboxes +// Filled in at initialization from translated strings +// +std::string USE_TEXTURE_LABEL; // subtly different (and more clear) name from llpanelface.cpp to avoid clashes -Zi + +FSPanelFace::FSPanelFace() : + LLPanel(), + mNeedMediaTitle(true), + mUnsavedChanges(0) +{ + // register callbacks before buildFromFile() or they won't work! + mCommitCallbackRegistrar.add("BuildTool.Flip", boost::bind(&FSPanelFace::onCommitFlip, this, _2)); + mCommitCallbackRegistrar.add("BuildTool.GLTFUVSpinner", boost::bind(&FSPanelFace::onCommitGLTFUVSpinner, this, _1, _2)); + mCommitCallbackRegistrar.add("BuildTool.SelectSameTexture", boost::bind(&FSPanelFace::onClickBtnSelectSameTexture, this, _1, _2)); + mCommitCallbackRegistrar.add("BuildTool.ShowFindAllButton", boost::bind(&FSPanelFace::onShowFindAllButton, this, _1, _2)); + mCommitCallbackRegistrar.add("BuildTool.HideFindAllButton", boost::bind(&FSPanelFace::onHideFindAllButton, this, _1, _2)); + + buildFromFile("panel_fs_tools_texture.xml"); + + USE_TEXTURE_LABEL = LLTrans::getString("use_texture"); +} + +FSPanelFace::~FSPanelFace() +{ + unloadMedia(); +} + +// +// Methods +// + +// make sure all referenced UI controls are actually present in the skin +// and if not, terminate immediately with the line number of the error, +// so the skin creator will be alerted that something is wrong, and the +// rest of the code can assume all UI controls are actually there -Zi +#define SKIN_CHECK(x) if ( !(x) ) { skin_error(__LINE__); } + +void skin_error(int line) +{ + LL_ERRS("BuildTool") << "Skin error in line: " << line << LL_ENDL; +} + +void FSPanelFace::onMatTabChange() +{ + static S32 last_mat = -1; + if( auto curr_mat = getCurrentMaterialType(); curr_mat != last_mat ) + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + LLViewerObject* objectp = node ? node->getObject() : NULL; + if(objectp) + { + last_mat = curr_mat; + gSavedSettings.setBOOL("FSShowSelectedInBlinnPhong", (curr_mat == MATMEDIA_MATERIAL)); + objectp->markForUpdate(); + objectp->faceMappingChanged(); + } + } +} + +BOOL FSPanelFace::postBuild() +{ + // + // grab pointers to all relevant UI elements here and verify they are good + // + + // Tab controls + SKIN_CHECK(mTabsPBRMatMedia = findChild("tabs_material_type")); + SKIN_CHECK(mTabsMatChannel = findChild("tabs_blinn_phong_uvs")); + SKIN_CHECK(mTabsPBRChannel = findChild("tabs_pbr_transforms")); + + // common controls and parameters for Blinn-Phong and PBR + SKIN_CHECK(mBtnCopyFaces = findChild("copy_face_btn")); + SKIN_CHECK(mBtnPasteFaces = findChild("paste_face_btn")); + SKIN_CHECK(mCtrlGlow = findChild("glow")); + SKIN_CHECK(mCtrlRpt = findChild("rptctrl")); + + // Blinn-Phong alpha parameters + SKIN_CHECK(mCtrlColorTransp = findChild("ColorTrans")); + SKIN_CHECK(mColorTransPercent = findChild("color trans percent")); + SKIN_CHECK(mLabelAlphaMode = findChild("label alphamode")); + SKIN_CHECK(mComboAlphaMode = findChild("combobox alphamode")); + SKIN_CHECK(mCtrlMaskCutoff = findChild("maskcutoff")); + SKIN_CHECK(mCheckFullbright = findChild("checkbox fullbright")); + + // Blinn-Phong texture transforms and controls + SKIN_CHECK(mLabelTexGen = findChild("tex gen")); + SKIN_CHECK(mComboTexGen = findChild("combobox texgen")); + SKIN_CHECK(mCheckPlanarAlign = findChild("checkbox planar align")); + SKIN_CHECK(mLabelBumpiness = findChild("label bumpiness")); + SKIN_CHECK(mComboBumpiness = findChild("combobox bumpiness")); + SKIN_CHECK(mLabelShininess = findChild("label shininess")); + SKIN_CHECK(mComboShininess = findChild("combobox shininess")); + SKIN_CHECK(mCtrlTexScaleU = findChild("TexScaleU")); + SKIN_CHECK(mCtrlTexScaleV = findChild("TexScaleV")); + SKIN_CHECK(mCtrlTexOffsetU = findChild("TexOffsetU")); + SKIN_CHECK(mCtrlTexOffsetV = findChild("TexOffsetV")); + SKIN_CHECK(mCtrlTexRot = findChild("TexRot")); + SKIN_CHECK(mCtrlBumpyScaleU = findChild("bumpyScaleU")); + SKIN_CHECK(mCtrlBumpyScaleV = findChild("bumpyScaleV")); + SKIN_CHECK(mCtrlBumpyOffsetU = findChild("bumpyOffsetU")); + SKIN_CHECK(mCtrlBumpyOffsetV = findChild("bumpyOffsetV")); + SKIN_CHECK(mCtrlBumpyRot = findChild("bumpyRot")); + SKIN_CHECK(mCtrlShinyScaleU = findChild("shinyScaleU")); + SKIN_CHECK(mCtrlShinyScaleV = findChild("shinyScaleV")); + SKIN_CHECK(mCtrlShinyOffsetU = findChild("shinyOffsetU")); + SKIN_CHECK(mCtrlShinyOffsetV = findChild("shinyOffsetV")); + SKIN_CHECK(mCtrlShinyRot = findChild("shinyRot")); + SKIN_CHECK(mCtrlGlossiness = findChild("glossiness")); + SKIN_CHECK(mCtrlEnvironment = findChild("environment")); + + // Blinn-Phong Diffuse tint color swatch + SKIN_CHECK(mColorSwatch = findChild("colorswatch")); + + // Blinn-Phong Diffuse texture swatch + SKIN_CHECK(mTextureCtrl = findChild("texture control")); + + // Blinn-Phong Normal texture swatch + SKIN_CHECK(mBumpyTextureCtrl = findChild("bumpytexture control")); + + // Blinn-Phong Specular texture swatch + SKIN_CHECK(mShinyTextureCtrl = findChild("shinytexture control")); + + // Blinn-Phong Specular tint color swatch + SKIN_CHECK(mShinyColorSwatch = findChild("shinycolorswatch")); + + // Texture alignment and maps synchronization + SKIN_CHECK(mBtnAlignMedia = findChild("button align")); + SKIN_CHECK(mBtnAlignTextures = findChild("button align textures")); + SKIN_CHECK(mCheckSyncMaterials = findChild("checkbox_sync_settings")) + + // Media + SKIN_CHECK(mBtnDeleteMedia = findChild("delete_media")); + SKIN_CHECK(mBtnAddMedia = findChild("add_media")); + SKIN_CHECK(mTitleMedia = findChild("title_media")); + SKIN_CHECK(mTitleMediaText = findChild("media_info")); + + // PBR + SKIN_CHECK(mMaterialCtrlPBR = findChild("pbr_control")); + SKIN_CHECK(mBaseTexturePBR = findChild("base_color_picker")); + SKIN_CHECK(mBaseTintPBR = findChild("base_color_tint_picker")); + SKIN_CHECK(mNormalTexturePBR = findChild("normal_map_picker")); + SKIN_CHECK(mORMTexturePBR = findChild("metallic_map_picker")); + SKIN_CHECK(mEmissiveTexturePBR = findChild("emissive_map_picker")); + SKIN_CHECK(mEmissiveTintPBR = findChild("emissive_color_tint_picker")); + SKIN_CHECK(mCheckDoubleSidedPBR = findChild("double sided")); + SKIN_CHECK(mAlphaPBR = findChild("transparency")); + SKIN_CHECK(mLabelAlphaModePBR = findChild("blend mode label")); + SKIN_CHECK(mAlphaModePBR = findChild("alpha mode")); + SKIN_CHECK(mMaskCutoffPBR = findChild("alpha cutoff")); + SKIN_CHECK(mMetallicFactorPBR = findChild("metalness factor")); + SKIN_CHECK(mRoughnessFactorPBR = findChild("roughness factor")); + SKIN_CHECK(mBtnSavePBR = findChild("save_selected_pbr")); + + // + // hook up callbacks and do setup of all relevant UI elements here + // + mTabsPBRMatMedia->setCommitCallback(boost::bind(&FSPanelFace::onMatTabChange, this)); + // common controls and parameters for Blinn-Phong and PBR + mBtnCopyFaces->setCommitCallback(boost::bind(&FSPanelFace::onCopyFaces, this)); + mBtnPasteFaces->setCommitCallback(boost::bind(&FSPanelFace::onPasteFaces, this)); + mCtrlGlow->setCommitCallback(boost::bind(&FSPanelFace::onCommitGlow, this)); + mCtrlRpt->setCommitCallback(boost::bind(&FSPanelFace::onCommitRepeatsPerMeter, this)); + + // Blinn-Phong alpha parameters + mCtrlColorTransp->setCommitCallback(boost::bind(&FSPanelFace::onCommitAlpha, this)); + mComboAlphaMode->setCommitCallback(boost::bind(&FSPanelFace::onCommitAlphaMode, this)); + mCtrlMaskCutoff->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialMaskCutoff, this)); + mCheckFullbright->setCommitCallback(boost::bind(&FSPanelFace::onCommitFullbright, this)); + + // Blinn-Phong texture transforms and controls + mComboTexGen->setCommitCallback(boost::bind(&FSPanelFace::onCommitTexGen, this)); + mCheckPlanarAlign->setCommitCallback(boost::bind(&FSPanelFace::onCommitPlanarAlign, this)); + mComboBumpiness->setCommitCallback(boost::bind(&FSPanelFace::onCommitBump, this)); + mComboShininess->setCommitCallback(boost::bind(&FSPanelFace::onCommitShiny, this)); + mCtrlTexScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureScaleX, this)); + mCtrlTexScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureScaleY, this)); + mCtrlTexOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureOffsetX, this)); + mCtrlTexOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureOffsetY, this)); + mCtrlTexRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureRot, this)); + mCtrlBumpyScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyScaleX, this)); + mCtrlBumpyScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyScaleY, this)); + mCtrlBumpyOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyOffsetX, this)); + mCtrlBumpyOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyOffsetY, this)); + mCtrlBumpyRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyRot, this)); + mCtrlShinyScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyScaleX, this)); + mCtrlShinyScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyScaleY, this)); + mCtrlShinyOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyOffsetX, this)); + mCtrlShinyOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyOffsetY, this)); + mCtrlShinyRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyRot, this)); + mCtrlGlossiness->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialGloss, this)); + mCtrlEnvironment->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialEnv, this)); + + // Blinn-Phong Diffuse tint color swatch + mColorSwatch->setCommitCallback(boost::bind(&FSPanelFace::onCommitColor, this)); + mColorSwatch->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelColor, this)); + mColorSwatch->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectColor, this)); + + // Blinn-Phong Diffuse texture swatch + mTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_TEXTURE); + mTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitTexture, this, _1, _2)); + mTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelTexture, this)); + mTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2)); + mTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2)); + mTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + + // Blinn-Phong Normal texture swatch + mBumpyTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_NORMAL); + mBumpyTextureCtrl->setBlankImageAssetID(BLANK_OBJECT_NORMAL); + mBumpyTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitNormalTexture, this, _1, _2)); + mBumpyTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelNormalTexture, this)); + mBumpyTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2)); + mBumpyTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2)); + mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mBumpyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + + // Blinn-Phong Specular texture swatch + mShinyTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_SPECULAR); + mShinyTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitSpecularTexture, this, _1, _2)); + mShinyTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelSpecularTexture, this)); + mShinyTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2)); + mShinyTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2)); + mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mShinyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + + // Blinn-Phong Specular tint color swatch + mShinyColorSwatch->setCommitCallback(boost::bind(&FSPanelFace::onCommitShinyColor, this)); + mShinyColorSwatch->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelShinyColor, this)); + mShinyColorSwatch->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectShinyColor, this)); + mShinyColorSwatch->setCanApplyImmediately(TRUE); + + // Texture alignment and maps synchronization + mBtnAlignMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickAutoFix, this)); + mBtnAlignTextures->setCommitCallback(boost::bind(&FSPanelFace::onAlignTexture, this)); + mCheckSyncMaterials->setCommitCallback(boost::bind(&FSPanelFace::onClickMapsSync, this)); + + // Media + mBtnDeleteMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnDeleteMedia, this)); + mBtnAddMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnAddMedia, this)); + + // PBR Base Material swatch + // mMaterialCtrlPBR->setDefaultImageAssetID(LLUUID::null); // we have no default material, and null is standard for LLUUID -Zi + mMaterialCtrlPBR->setBlankImageAssetID(LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID); + mMaterialCtrlPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this)); + mMaterialCtrlPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this)); + mMaterialCtrlPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this)); + mMaterialCtrlPBR->setDragCallback(boost::bind(&FSPanelFace::onDragPbr, this, _2)); + mMaterialCtrlPBR->setOnTextureSelectedCallback(boost::bind(&FSPanelFace::onPbrSelectionChanged, this, _1)); + mMaterialCtrlPBR->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2)); + mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_NONE); + mMaterialCtrlPBR->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + mMaterialCtrlPBR->setBakeTextureEnabled(false); + mMaterialCtrlPBR->setInventoryPickType(PICK_MATERIAL); + + // PBR Base Color texture swatch + mBaseTexturePBR->setDefaultImageAssetID(DEFAULT_OBJECT_TEXTURE); + mBaseTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mBaseTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mBaseTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Base Color tint color swatch + mBaseTintPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mBaseTintPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mBaseTintPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Base Normal map swatch + mNormalTexturePBR->setDefaultImageAssetID(DEFAULT_OBJECT_NORMAL); + mNormalTexturePBR->setBlankImageAssetID(BLANK_OBJECT_NORMAL); + mNormalTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mNormalTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mNormalTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Base Emissive map swatch + mEmissiveTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mEmissiveTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mEmissiveTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Emissive tint color swatch + mEmissiveTintPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mEmissiveTintPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mEmissiveTintPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR Base (O)RM map swatch + mORMTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mORMTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1)); + mORMTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1)); + + // PBR parameters + mCheckDoubleSidedPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mAlphaPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mAlphaModePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mMaskCutoffPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mMetallicFactorPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + mRoughnessFactorPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1)); + + // PBR Save material button + mBtnSavePBR->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnSavePBR, this)); + + // Only allow fully permissive textures + if (!gAgent.isGodlike()) + { + mBaseTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mNormalTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mORMTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + mEmissiveTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER); + } + + // + // set up user interface + // + + LLGLTFMaterialList::addSelectionUpdateCallback(onMaterialOverrideReceived); + sMaterialOverrideSelection.connect(); + + changePrecision(gSavedSettings.getS32("FSBuildToolDecimalPrecision")); + + selectMaterialType(MATMEDIA_PBR); // TODO: add tab switching signal + selectMatChannel(MATTYPE_DIFFUSE); // TODO: add tab switching signal + selectPBRChannel(PBRTYPE_RENDER_MATERIAL_ID); // TODO: add tab switching signal + + return TRUE; +} + +// +// Things the UI provides... +// + +LLUUID FSPanelFace::getCurrentNormalMap() { return mBumpyTextureCtrl->getImageAssetID(); } +LLUUID FSPanelFace::getCurrentSpecularMap() { return mShinyTextureCtrl->getImageAssetID(); } +U32 FSPanelFace::getCurrentShininess() { return mComboShininess->getCurrentIndex(); } +U32 FSPanelFace::getCurrentBumpiness() { return mComboBumpiness->getCurrentIndex(); } +U8 FSPanelFace::getCurrentDiffuseAlphaMode() { return (U8)mComboAlphaMode->getCurrentIndex(); } +U8 FSPanelFace::getCurrentAlphaMaskCutoff() { return (U8)mCtrlMaskCutoff->getValue().asInteger(); } +U8 FSPanelFace::getCurrentEnvIntensity() { return (U8)mCtrlEnvironment->getValue().asInteger(); } +U8 FSPanelFace::getCurrentGlossiness() { return (U8)mCtrlGlossiness->getValue().asInteger(); } +F32 FSPanelFace::getCurrentBumpyRot() { return mCtrlBumpyRot->getValue().asReal(); } +F32 FSPanelFace::getCurrentBumpyScaleU() { return mCtrlBumpyScaleU->getValue().asReal(); } +F32 FSPanelFace::getCurrentBumpyScaleV() { return mCtrlBumpyScaleV->getValue().asReal(); } +F32 FSPanelFace::getCurrentBumpyOffsetU() { return mCtrlBumpyOffsetU->getValue().asReal(); } +F32 FSPanelFace::getCurrentBumpyOffsetV() { return mCtrlBumpyOffsetV->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyRot() { return mCtrlShinyRot->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyScaleU() { return mCtrlShinyScaleU->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyScaleV() { return mCtrlShinyScaleV->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyOffsetU() { return mCtrlShinyOffsetU->getValue().asReal(); } +F32 FSPanelFace::getCurrentShinyOffsetV() { return mCtrlShinyOffsetV->getValue().asReal(); } + +// UI provided diffuse parameters +F32 FSPanelFace::getCurrentTextureRot() { return mCtrlTexRot->getValue().asReal(); } +F32 FSPanelFace::getCurrentTextureScaleU() { return mCtrlTexScaleU->getValue().asReal(); } +F32 FSPanelFace::getCurrentTextureScaleV() { return mCtrlTexScaleV->getValue().asReal(); } +F32 FSPanelFace::getCurrentTextureOffsetU() { return mCtrlTexOffsetU->getValue().asReal(); } +F32 FSPanelFace::getCurrentTextureOffsetV() { return mCtrlTexOffsetV->getValue().asReal(); } +// + +LLRender::eTexIndex FSPanelFace::getTextureChannelToEdit() +{ + LLRender::eTexIndex channel_to_edit = LLRender::DIFFUSE_MAP; + + S32 matmedia_selection = getCurrentMaterialType(); + + if (matmedia_selection == MATMEDIA_MATERIAL) + { + channel_to_edit = (LLRender::eTexIndex) getCurrentMatChannel(); + + if (channel_to_edit == LLRender::NORMAL_MAP && getCurrentNormalMap().isNull()) return LLRender::DIFFUSE_MAP; + if (channel_to_edit == LLRender::SPECULAR_MAP && getCurrentSpecularMap().isNull()) return LLRender::DIFFUSE_MAP; + } + + // this is technically not correct, the return type is not the same, which forces us to cast -Zi + else if (matmedia_selection == MATMEDIA_PBR) + { + channel_to_edit = (LLRender::eTexIndex) getCurrentPBRChannel(); + + if (channel_to_edit == PBRTYPE_NORMAL && mNormalTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR; + if (channel_to_edit == PBRTYPE_METALLIC_ROUGHNESS && mORMTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR; + if (channel_to_edit == PBRTYPE_EMISSIVE && mEmissiveTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR; + } + + return channel_to_edit; +} + +LLRender::eTexIndex FSPanelFace::getTextureDropChannel() +{ + if (getCurrentMaterialType() == MATMEDIA_MATERIAL) + { + return getTextureChannelToEdit(); + } + + return LLRender::eTexIndex(MATTYPE_DIFFUSE); +} + +LLGLTFMaterial::TextureInfo FSPanelFace::getPBRDropChannel() +{ + if (getCurrentMaterialType() == MATMEDIA_PBR) + { + S32 current_pbr_channel = getCurrentPBRChannel(); + if (current_pbr_channel == PBRTYPE_NORMAL) return LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL; + if (current_pbr_channel == PBRTYPE_METALLIC_ROUGHNESS) return LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS; + if (current_pbr_channel == PBRTYPE_EMISSIVE) return LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE; + } + return LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR; +} + +LLMaterialPtr FSPanelFace::createDefaultMaterial(LLMaterialPtr current_material) +{ + LLMaterialPtr new_material(current_material.notNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial()); + llassert_always(new_material); + + // Preserve old diffuse alpha mode or assert correct default blend mode as appropriate for the alpha channel content of the diffuse texture + // + new_material->setDiffuseAlphaMode(current_material.isNull() ? (isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE) : current_material->getDiffuseAlphaMode()); + return new_material; +} + +void FSPanelFace::onVisibilityChange(BOOL new_visibility) +{ + if (new_visibility) + { + gAgent.showLatestFeatureNotification("gltf"); + } + LLPanel::onVisibilityChange(new_visibility); +} + +void FSPanelFace::draw() +{ + // TODO(Beq) why does it have to call applyTE? + updateCopyTexButton(); + + // grab media name/title and update the UI widget + // Todo: move it, it's preferable not to update + // labels inside draw + updateMediaTitle(); + + LLPanel::draw(); + + // not sure if there isn't a better place for this, but for the time being this seems to work, + // and trying other places always failed in some way or other -Zi + static U64MicrosecondsImplicit next_update_time = 0LL; + if (mUnsavedChanges && gFrameTime > next_update_time) + { + LL_DEBUGS("APPLY_GLTF_CHANGES") << "detected unsaved changes: " << mUnsavedChanges << LL_ENDL; + + LLPointer mat = new LLGLTFMaterial(); + getGLTFMaterial(mat); + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + LLRenderMaterialOverrideFunctor override_func(mat, mUnsavedChanges); + selected_objects->applyToNodes(&override_func); + + LLGLTFMaterialList::flushUpdates(); + + mUnsavedChanges = 0; + + next_update_time = gFrameTime + 100000LL; // 100 ms + + // delete mat; // do not delete mat, it's still referenced elsewhere (probably in the material list) -Zi + } + + if (sMaterialOverrideSelection.update()) + { + setMaterialOverridesFromSelection(); + updatePBROverrideDisplay(); + } +} + +void FSPanelFace::sendTexture() +{ + if (!mTextureCtrl->getTentative()) + { + // we grab the item id first, because we want to do a + // permissions check in the selection manager. ARGH! + LLUUID id = mTextureCtrl->getImageItemID(); + if (id.isNull()) + { + id = mTextureCtrl->getImageAssetID(); + } + if (!LLSelectMgr::getInstance()->selectionSetImage(id, getCurrentMaterialType()==MATMEDIA_PBR) ) + { + // need to refresh value in texture ctrl + refresh(); + } + } +} + +void FSPanelFace::sendBump(U32 bumpiness) +{ + if (bumpiness < BUMPY_TEXTURE) + { + LL_DEBUGS("Materials") << "clearing bumptexture control" << LL_ENDL; + mBumpyTextureCtrl->clear(); + mBumpyTextureCtrl->setImageAssetID(LLUUID()); + } + + updateBumpyControls(bumpiness == BUMPY_TEXTURE, true); + + LLUUID current_normal_map = mBumpyTextureCtrl->getImageAssetID(); + + U8 bump = (U8)bumpiness & TEM_BUMP_MASK; + + // Clear legacy bump to None when using an actual normal map + // + if (!current_normal_map.isNull()) + { + bump = 0; + } + + // Set the normal map or reset it to null as appropriate + // + LLSelectedTEMaterial::setNormalID(this, current_normal_map); + LLSelectMgr::getInstance()->selectionSetBumpmap(bump, mBumpyTextureCtrl->getImageItemID()); +} + +void FSPanelFace::sendTexGen() +{ + U8 tex_gen = (U8) mComboTexGen->getCurrentIndex() << TEM_TEX_GEN_SHIFT; + LLSelectMgr::getInstance()->selectionSetTexGen(tex_gen); +} + +void FSPanelFace::sendShiny(U32 shininess) +{ + if (shininess < SHINY_TEXTURE) + { + mShinyTextureCtrl->clear(); + mShinyTextureCtrl->setImageAssetID(LLUUID()); + } + + LLUUID specmap = getCurrentSpecularMap(); + + U8 shiny = (U8)shininess & TEM_SHINY_MASK; + if (!specmap.isNull()) + { + shiny = 0; + } + + LLSelectedTEMaterial::setSpecularID(this, specmap); + LLSelectMgr::getInstance()->selectionSetShiny(shiny, mShinyTextureCtrl->getImageItemID()); + + updateShinyControls(!specmap.isNull(), true); +} + +void FSPanelFace::sendFullbright() +{ + U8 fullbright = mCheckFullbright->get() ? TEM_FULLBRIGHT_MASK : 0; + LLSelectMgr::getInstance()->selectionSetFullbright(fullbright); +} + +void FSPanelFace::sendColor() +{ + LLSelectMgr::getInstance()->selectionSetColorOnly(mColorSwatch->get()); +} + +void FSPanelFace::sendAlpha() +{ + F32 alpha = (100.0f - mCtrlColorTransp->get()) / 100.0f; + LLSelectMgr::getInstance()->selectionSetAlphaOnly(alpha); +} + +void FSPanelFace::sendGlow() +{ + LLSelectMgr::getInstance()->selectionSetGlow(mCtrlGlow->get()); +} + +struct FSPanelFaceSetTEFunctor : public LLSelectedTEFunctor +{ + FSPanelFaceSetTEFunctor(FSPanelFace* panel) : + mPanel(panel) + { + } + + virtual bool apply(LLViewerObject* object, S32 te) + { + BOOL valid; + F32 value; + std::string prefix; + + // Effectively the same as MATMEDIA_PBR - separate for the sake of clarity + + const std::string& tab_name = mPanel->mTabsMatChannel->getCurrentPanel()->getName(); + + prefix = "Tex"; + if (tab_name == "panel_blinn_phong_normal") + { + prefix = "bumpy"; + } + else if (tab_name == "panel_blinn_phong_specular") + { + prefix = "shiny"; + } + + LLSpinCtrl* ctrlTexScaleS = mPanel->findChild(prefix + "ScaleU"); + LLSpinCtrl* ctrlTexScaleT = mPanel->findChild(prefix + "ScaleV"); + LLSpinCtrl* ctrlTexOffsetS = mPanel->findChild(prefix + "OffsetU"); + LLSpinCtrl* ctrlTexOffsetT = mPanel->findChild(prefix + "OffsetV"); + LLSpinCtrl* ctrlTexRotation = mPanel->findChild(prefix + "Rot"); + + bool align_planar = mPanel->mCheckPlanarAlign->get(); + + llassert(comboTexGen); + llassert(object); + + if (ctrlTexScaleS) + { + valid = !ctrlTexScaleS->getTentative(); + if (valid || align_planar) + { + value = ctrlTexScaleS->get(); + if (mPanel->mComboTexGen->getCurrentIndex() == 1) + { + value *= 0.5f; + } + object->setTEScaleS(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, value, te, object->getID()); + } + } + } + + if (ctrlTexScaleT) + { + valid = !ctrlTexScaleT->getTentative(); + if (valid || align_planar) + { + value = ctrlTexScaleT->get(); + if (mPanel->mComboTexGen->getCurrentIndex() == 1) + { + value *= 0.5f; + } + object->setTEScaleT(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, value, te, object->getID()); + } + } + } + + if (ctrlTexOffsetS) + { + valid = !ctrlTexOffsetS->getTentative(); + if (valid || align_planar) + { + value = ctrlTexOffsetS->get(); + object->setTEOffsetS(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, value, te, object->getID()); + } + } + } + + if (ctrlTexOffsetT) + { + valid = !ctrlTexOffsetT->getTentative(); + if (valid || align_planar) + { + value = ctrlTexOffsetT->get(); + object->setTEOffsetT(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, value, te, object->getID()); + } + } + } + + if (ctrlTexRotation) + { + valid = !ctrlTexRotation->getTentative(); + if (valid || align_planar) + { + value = ctrlTexRotation->get() * DEG_TO_RAD; + object->setTERotation(te, value); + + if (align_planar) + { + FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, value, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, value, te, object->getID()); + } + } + } + return true; + } +private: + FSPanelFace* mPanel; +}; + +// Functor that aligns a face to mCenterFace +struct FSPanelFaceSetAlignedTEFunctor : public LLSelectedTEFunctor +{ + FSPanelFaceSetAlignedTEFunctor(FSPanelFace* panel, LLFace* center_face) : + mPanel(panel), + mCenterFace(center_face) + { + } + + virtual bool apply(LLViewerObject* object, S32 te) + { + LLFace* facep = object->mDrawable->getFace(te); + if (!facep) + { + return true; + } + + if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te) + { + return true; + } + + bool set_aligned = true; + if (facep == mCenterFace) + { + set_aligned = false; + } + if (set_aligned) + { + LLVector2 uv_offset, uv_scale; + F32 uv_rot; + set_aligned = facep->calcAlignedPlanarTE(mCenterFace, &uv_offset, &uv_scale, &uv_rot); + if (set_aligned) + { + object->setTEOffset(te, uv_offset.mV[VX], uv_offset.mV[VY]); + object->setTEScale(te, uv_scale.mV[VX], uv_scale.mV[VY]); + object->setTERotation(te, uv_rot); + + FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, uv_rot, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, uv_rot, te, object->getID()); + + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, uv_offset.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, uv_offset.mV[VY], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); + + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, uv_offset.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, uv_offset.mV[VY], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); + } + } + if (!set_aligned) + { + FSPanelFaceSetTEFunctor setfunc(mPanel); + setfunc.apply(object, te); + } + return true; + } +private: + FSPanelFace* mPanel; + LLFace* mCenterFace; +}; + +struct FSPanelFaceSetAlignedConcreteTEFunctor : public LLSelectedTEFunctor +{ + FSPanelFaceSetAlignedConcreteTEFunctor(FSPanelFace* panel, LLFace* center_face, LLRender::eTexIndex map) : + mPanel(panel), + mChefFace(center_face), + mMap(map) + { + } + + virtual bool apply(LLViewerObject* object, S32 te) + { + LLFace* facep = object->mDrawable->getFace(te); + if (!facep) + { + return true; + } + + if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te) + { + return true; + } + + if (mChefFace != facep) + { + LLVector2 uv_offset, uv_scale; + F32 uv_rot; + if (facep->calcAlignedPlanarTE(mChefFace, &uv_offset, &uv_scale, &uv_rot, mMap)) + { + switch (mMap) + { + case LLRender::DIFFUSE_MAP: + object->setTEOffset(te, uv_offset.mV[VX], uv_offset.mV[VY]); + object->setTEScale(te, uv_scale.mV[VX], uv_scale.mV[VY]); + object->setTERotation(te, uv_rot); + break; + + case LLRender::NORMAL_MAP: + FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, uv_rot, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, uv_offset.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, uv_offset.mV[VY], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); + break; + + case LLRender::SPECULAR_MAP: + FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, uv_rot, te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, uv_offset.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, uv_offset.mV[VY], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID()); + FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID()); + break; + + default: /*make compiler happy*/ + break; + } + } + } + + return true; + } + + private: + FSPanelFace* mPanel; + LLFace* mChefFace; + LLRender::eTexIndex mMap; +}; + +// Functor that tests if a face is aligned to mCenterFace +struct FSPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor +{ + FSPanelFaceGetIsAlignedTEFunctor(LLFace* center_face) : + mCenterFace(center_face) + { + } + + virtual bool apply(LLViewerObject* object, S32 te) + { + LLFace* facep = object->mDrawable->getFace(te); + if (!facep) + { + return false; + } + + if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te) + { //volume face does not exist, can't be aligned + return false; + } + + if (facep == mCenterFace) + { + return true; + } + + LLVector2 aligned_st_offset, aligned_st_scale; + F32 aligned_st_rot; + if ( facep->calcAlignedPlanarTE(mCenterFace, &aligned_st_offset, &aligned_st_scale, &aligned_st_rot) ) + { + const LLTextureEntry* tep = facep->getTextureEntry(); + LLVector2 st_offset, st_scale; + tep->getOffset(&st_offset.mV[VX], &st_offset.mV[VY]); + tep->getScale(&st_scale.mV[VX], &st_scale.mV[VY]); + F32 st_rot = tep->getRotation(); + + bool eq_offset_x = is_approx_equal_fraction(st_offset.mV[VX], aligned_st_offset.mV[VX], 12); + bool eq_offset_y = is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 12); + bool eq_scale_x = is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 12); + bool eq_scale_y = is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 12); + bool eq_rot = is_approx_equal_fraction(st_rot, aligned_st_rot, 6); + + // needs a fuzzy comparison, because of fp errors + if (eq_offset_x && + eq_offset_y && + eq_scale_x && + eq_scale_y && + eq_rot) + { + return true; + } + } + return false; + } + private: + LLFace* mCenterFace; +}; + +struct FSPanelFaceSendFunctor : public LLSelectedObjectFunctor +{ + virtual bool apply(LLViewerObject* object) + { + object->sendTEUpdate(); + return true; + } +}; + +void FSPanelFace::sendTextureInfo() +{ + if (mCheckPlanarAlign->getValue().asBoolean()) + { + LLFace* last_face = NULL; + bool identical_face =false; + LLSelectedTE::getFace(last_face, identical_face); + FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + } + else + { + FSPanelFaceSetTEFunctor setfunc(this); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + } + + FSPanelFaceSendFunctor sendfunc; + LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc); +} + +void FSPanelFace::alignTextureLayer() +{ + LLFace* last_face = NULL; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); + + // TODO: make this respect PBR channels -Zi + FSPanelFaceSetAlignedConcreteTEFunctor setfunc(this, last_face, getTextureChannelToEdit()); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); +} + +void FSPanelFace::getState() +{ + updateUI(); +} + +void FSPanelFace::updateUI(bool force_set_values /*false*/) +{ //set state of UI to match state of texture entry(ies) (calls setEnabled, setValue, etc, but NOT setVisible) + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + LLViewerObject* objectp = node ? node->getObject() : NULL; + + if (objectp + && objectp->getPCode() == LL_PCODE_VOLUME + && objectp->permModify()) + { + // TODO: Find out what "permanent" objects are supposed to allow to be edited. Right now this will + // completely blank out the texture panel, so we could just move that into the if() above -Zi + bool editable = !objectp->isPermanentEnforced(); + bool attachment = objectp->isAttachment(); + + // this object's faces can potentially be edited by us, so display the edit controls unless this is + // a "permanent" pathfinding(?) object -Zi + gSavedSettings.setBOOL("FSInternalCanEditObjectFaces", editable); + LL_DEBUGS("ENABLEDISABLETOOLS") << "show face edit controls: " << editable << LL_ENDL; + + // TODO: editable always true here so we don't have to go through all the following code and strip it out + // until we know what the permanent thing abobe is supposed to do and we know if blanking out all + // controls has any unforseen side effects to editing. -Zi + editable = true; + + bool has_pbr_material; + bool has_faces_without_pbr; + updateUIGLTF(objectp, has_pbr_material, has_faces_without_pbr, force_set_values); + + // TODO: if has_pbr_material AND has_faces_without_pbr give "Mixed Selection!" warning somehow + + mTabsPBRMatMedia->enableTabButton( + mTabsPBRMatMedia->getIndexForPanel( + mTabsPBRMatMedia->getPanelByName("panel_material_type_blinn_phong")), editable ); + + // only turn on auto-adjust button if there is a media renderer and the media is loaded + mBtnAlignMedia->setEnabled(editable); + + bool enable_material_controls = (!gSavedSettings.getBOOL("SyncMaterialSettings")); + + // *NOTE: The "identical" variable is currently only used to decide if + // the texgen control should be tentative - this is not used by GLTF + // materials. -Cosmic;2022-11-09 + bool identical = true; // true because it is anded below + bool identical_diffuse = false; + bool identical_norm = false; + bool identical_spec = false; + + LLUUID id; + LLUUID normmap_id; + LLUUID specmap_id; + + LLSelectedTE::getTexId(id, identical_diffuse); + LLSelectedTEMaterial::getNormalID(normmap_id, identical_norm); + LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec); + + mTabsMatChannel->setEnabled(editable); + mTabsPBRChannel->setEnabled(editable); + + mCheckSyncMaterials->setEnabled(editable); + mCheckSyncMaterials->setValue(gSavedSettings.getBOOL("SyncMaterialSettings")); + + updateVisibility(objectp); + + LLColor4 color = LLColor4::white; + bool identical_color = false; + + LLSelectedTE::getColor(color, identical_color); + LLColor4 prev_color = mColorSwatch->get(); + + mColorSwatch->setOriginal(color); + mColorSwatch->set(color, force_set_values || (prev_color != color) || !editable); + + mColorSwatch->setValid(editable); + mColorSwatch->setEnabled(editable); + mColorSwatch->setCanApplyImmediately( editable ); + + F32 transparency = (1.f - color.mV[VALPHA]) * 100.f; + mCtrlColorTransp->setValue(editable ? transparency : 0); + mCtrlColorTransp->setEnabled(editable ); + mColorTransPercent->setMouseOpaque(editable ); + + U8 shiny = 0; + // Shiny + { + bool identical_shiny = false; + + // Shiny - Legacy only, Blinn-Pbong specular is done further down + LLSelectedTE::getShiny(shiny, identical_shiny); + identical = identical && identical_shiny; + + shiny = specmap_id.isNull() ? shiny : SHINY_TEXTURE; + + mComboShininess->selectNthItem(shiny); + mComboShininess->setEnabled(editable); + mComboShininess->setTentative(!identical_shiny); + mLabelShininess->setEnabled(editable); + } + + U8 bumpy = 0; + // Bumpy + { + bool identical_bumpy = false; + LLSelectedTE::getBumpmap(bumpy, identical_bumpy); + + LLUUID norm_map_id = getCurrentNormalMap(); + + bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE; + + mComboBumpiness->selectNthItem(bumpy); + mComboBumpiness->setEnabled(editable); + mComboBumpiness->setTentative(!identical_bumpy); + mLabelBumpiness->setEnabled(editable); + } + + // Texture + { + mIsAlpha = false; + + LLGLenum image_format = GL_RGB; + bool identical_image_format = false; + LLSelectedTE::getImageFormat(image_format, identical_image_format); + + switch (image_format) + { + case GL_RGBA: + case GL_ALPHA: + { + mIsAlpha = true; + } + break; + + case GL_RGB: break; + default: + { + LL_WARNS() << "Unexpected tex format in FSPanelFace...resorting to no alpha" << LL_ENDL; + } + break; + } + + if (LLViewerMedia::getInstance()->textureHasMedia(id)) + { + mBtnAlignMedia->setEnabled(editable); + } + + if (identical_diffuse) + { + mTextureCtrl->setTentative(false); + mTextureCtrl->setEnabled(editable); + mTextureCtrl->setImageAssetID(id); + mComboAlphaMode->setEnabled(editable && mIsAlpha && transparency <= 0.f ); + mCtrlMaskCutoff->setEnabled(editable && mIsAlpha ); + + mTextureCtrl->setBakeTextureEnabled(true); + } + else if (id.isNull()) + { + // None selected + mTextureCtrl->setTentative(false); + mTextureCtrl->setEnabled(false); + mTextureCtrl->setImageAssetID(LLUUID::null); + mComboAlphaMode->setEnabled(false); + mCtrlMaskCutoff->setEnabled(false); + + mTextureCtrl->setBakeTextureEnabled(false); + } + else + { + // Tentative: multiple selected with different textures + mTextureCtrl->setTentative(true); + mTextureCtrl->setEnabled(editable ); + mTextureCtrl->setImageAssetID(id); + mComboAlphaMode->setEnabled(editable && mIsAlpha && transparency <= 0.f ); + mCtrlMaskCutoff->setEnabled(editable && mIsAlpha ); + + mTextureCtrl->setBakeTextureEnabled(true); + } + + mShinyTextureCtrl->setTentative(!identical_spec); + mShinyTextureCtrl->setEnabled(editable); + mShinyTextureCtrl->setImageAssetID(specmap_id); + + mBumpyTextureCtrl->setTentative(!identical_norm); + mBumpyTextureCtrl->setEnabled(editable ); + mBumpyTextureCtrl->setImageAssetID(normmap_id); + + if (attachment) + { + // attachments are in world and in inventory, + // server doesn't support changing permissions + // in such case + mTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + mShinyTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + } + else + { + mTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + } + + // Diffuse Alpha Mode + + // Init to the default that is appropriate for the alpha content of the asset + // + U8 alpha_mode = mIsAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + bool identical_alpha_mode = false; + + // See if that's been overridden by a material setting for same... + // + LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha); + + // it is invalid to have any alpha mode other than blend if transparency is greater than zero ... + // Want masking? Want emissive? Tough! You get BLEND! + alpha_mode = (transparency > 0.f) ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : alpha_mode; + + // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none + alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + mComboAlphaMode->selectNthItem(alpha_mode); + + updateAlphaControls(); + + mLabelAlphaMode->setEnabled(mComboAlphaMode->getEnabled()); + } + + // planar align + bool align_planar = mCheckPlanarAlign->get(); + bool identical_planar_aligned = false; + { + const bool texture_info_selected = (getCurrentMaterialType() == MATMEDIA_PBR && getCurrentPBRChannel() != PBRTYPE_RENDER_MATERIAL_ID); + const bool enabled = (editable && isIdenticalPlanarTexgen() && !texture_info_selected); + + mCheckPlanarAlign->setValue(align_planar && enabled); + mCheckPlanarAlign->setEnabled(enabled); + mBtnAlignTextures->setEnabled(enabled && LLSelectMgr::getInstance()->getSelection()->getObjectCount() > 1); + + if (align_planar && enabled) + { + LLFace* last_face = nullptr; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); + + FSPanelFaceGetIsAlignedTEFunctor get_is_aligend_func(last_face); + // this will determine if the texture param controls are tentative: + identical_planar_aligned = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&get_is_aligend_func); + } + } + + // Needs to be public and before tex scale settings below to properly reflect + // behavior when in planar vs default texgen modes in the + // NORSPEC-84 et al + // + LLTextureEntry::e_texgen selected_texgen = LLTextureEntry::TEX_GEN_DEFAULT; + bool identical_texgen = true; + bool identical_planar_texgen = false; + + { + LLSelectedTE::getTexGen(selected_texgen, identical_texgen); + identical_planar_texgen = (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR)); + } + + // Texture scale + { + bool identical_diff_scale_s = false; + bool identical_spec_scale_s = false; + bool identical_norm_scale_s = false; + + identical = align_planar ? identical_planar_aligned : identical; + + F32 diff_scale_s = 1.f; + F32 spec_scale_s = 1.f; + F32 norm_scale_s = 1.f; + + LLSelectedTE::getScaleS(diff_scale_s, identical_diff_scale_s); + LLSelectedTEMaterial::getSpecularRepeatX(spec_scale_s, identical_spec_scale_s); + LLSelectedTEMaterial::getNormalRepeatX(norm_scale_s, identical_norm_scale_s); + + diff_scale_s = editable ? diff_scale_s : 1.0f; + diff_scale_s *= identical_planar_texgen ? 2.0f : 1.0f; + + norm_scale_s = editable ? norm_scale_s : 1.0f; + norm_scale_s *= identical_planar_texgen ? 2.0f : 1.0f; + + spec_scale_s = editable ? spec_scale_s : 1.0f; + spec_scale_s *= identical_planar_texgen ? 2.0f : 1.0f; + + mCtrlTexScaleU->setValue(diff_scale_s); + mCtrlShinyScaleU->setValue(spec_scale_s); + mCtrlBumpyScaleU->setValue(norm_scale_s); + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexScaleU->setEnabled(editable && has_material); + + mCtrlShinyScaleU->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyScaleU->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + childSetEnabled("flipTextureScaleSU", mCtrlShinyScaleU->getEnabled()); + childSetEnabled("flipTextureScaleNU", mCtrlBumpyScaleU->getEnabled()); + */ + + bool diff_scale_tentative = !(identical && identical_diff_scale_s); + bool norm_scale_tentative = !(identical && identical_norm_scale_s); + bool spec_scale_tentative = !(identical && identical_spec_scale_s); + + mCtrlTexScaleU->setTentative( LLSD(diff_scale_tentative)); + mCtrlShinyScaleU->setTentative(LLSD(spec_scale_tentative)); + mCtrlBumpyScaleU->setTentative(LLSD(norm_scale_tentative)); + + mCheckSyncMaterials->setEnabled(editable && (specmap_id.notNull() || normmap_id.notNull()) && !align_planar); + } + + { + bool identical_diff_scale_t = false; + bool identical_spec_scale_t = false; + bool identical_norm_scale_t = false; + + F32 diff_scale_t = 1.f; + F32 spec_scale_t = 1.f; + F32 norm_scale_t = 1.f; + + LLSelectedTE::getScaleT(diff_scale_t, identical_diff_scale_t); + LLSelectedTEMaterial::getSpecularRepeatY(spec_scale_t, identical_spec_scale_t); + LLSelectedTEMaterial::getNormalRepeatY(norm_scale_t, identical_norm_scale_t); + + diff_scale_t = editable ? diff_scale_t : 1.0f; + diff_scale_t *= identical_planar_texgen ? 2.0f : 1.0f; + + norm_scale_t = editable ? norm_scale_t : 1.0f; + norm_scale_t *= identical_planar_texgen ? 2.0f : 1.0f; + + spec_scale_t = editable ? spec_scale_t : 1.0f; + spec_scale_t *= identical_planar_texgen ? 2.0f : 1.0f; + + bool diff_scale_tentative = !identical_diff_scale_t; + bool norm_scale_tentative = !identical_norm_scale_t; + bool spec_scale_tentative = !identical_spec_scale_t; + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexScaleV->setEnabled(editable && has_material); + + mCtrlShinyScaleV->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyScaleV->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + childSetEnabled("flipTextureScaleSV", mCtrlShinyScaleU->getEnabled()); + childSetEnabled("flipTextureScaleNV", mCtrlBumpyScaleU->getEnabled()); + */ + + if (force_set_values) + { + mCtrlTexScaleV->forceSetValue(diff_scale_t); + } + else + { + mCtrlTexScaleV->setValue(diff_scale_t); + } + mCtrlShinyScaleV->setValue(norm_scale_t); + mCtrlBumpyScaleV->setValue(spec_scale_t); + + mCtrlTexScaleV->setTentative(LLSD(diff_scale_tentative)); + mCtrlShinyScaleV->setTentative(LLSD(norm_scale_tentative)); + mCtrlBumpyScaleV->setTentative(LLSD(spec_scale_tentative)); + } + + // Texture offset + { + bool identical_diff_offset_s = false; + bool identical_norm_offset_s = false; + bool identical_spec_offset_s = false; + + F32 diff_offset_s = 0.0f; + F32 norm_offset_s = 0.0f; + F32 spec_offset_s = 0.0f; + + LLSelectedTE::getOffsetS(diff_offset_s, identical_diff_offset_s); + LLSelectedTEMaterial::getNormalOffsetX(norm_offset_s, identical_norm_offset_s); + LLSelectedTEMaterial::getSpecularOffsetX(spec_offset_s, identical_spec_offset_s); + + bool diff_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_diff_offset_s); + bool norm_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_norm_offset_s); + bool spec_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_spec_offset_s); + + mCtrlTexOffsetU->setValue( editable ? diff_offset_s : 0.0f); + mCtrlBumpyOffsetU->setValue(editable ? norm_offset_s : 0.0f); + mCtrlShinyOffsetU->setValue(editable ? spec_offset_s : 0.0f); + + mCtrlTexOffsetU->setTentative(LLSD(diff_offset_u_tentative)); + mCtrlBumpyOffsetU->setTentative(LLSD(norm_offset_u_tentative)); + mCtrlShinyOffsetU->setTentative(LLSD(spec_offset_u_tentative)); + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexOffsetU->setEnabled(editable && has_material); + + mCtrlShinyOffsetU->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyOffsetU->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + */ + } + + { + bool identical_diff_offset_t = false; + bool identical_norm_offset_t = false; + bool identical_spec_offset_t = false; + + F32 diff_offset_t = 0.0f; + F32 norm_offset_t = 0.0f; + F32 spec_offset_t = 0.0f; + + LLSelectedTE::getOffsetT(diff_offset_t, identical_diff_offset_t); + LLSelectedTEMaterial::getNormalOffsetY(norm_offset_t, identical_norm_offset_t); + LLSelectedTEMaterial::getSpecularOffsetY(spec_offset_t, identical_spec_offset_t); + + bool diff_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_diff_offset_t); + bool norm_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_norm_offset_t); + bool spec_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_spec_offset_t); + + mCtrlTexOffsetV->setValue( editable ? diff_offset_t : 0.0f); + mCtrlBumpyOffsetV->setValue(editable ? norm_offset_t : 0.0f); + mCtrlShinyOffsetV->setValue(editable ? spec_offset_t : 0.0f); + + mCtrlTexOffsetV->setTentative(LLSD(diff_offset_v_tentative)); + mCtrlBumpyOffsetV->setTentative(LLSD(norm_offset_v_tentative)); + mCtrlShinyOffsetV->setTentative(LLSD(spec_offset_v_tentative)); + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexOffsetV->setEnabled(editable && has_material); + + mCtrlShinyOffsetV->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyOffsetV->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + */ + } + + // Texture rotation + { + bool identical_diff_rotation = false; + bool identical_norm_rotation = false; + bool identical_spec_rotation = false; + + F32 diff_rotation = 0.f; + F32 norm_rotation = 0.f; + F32 spec_rotation = 0.f; + + LLSelectedTE::getRotation(diff_rotation,identical_diff_rotation); + LLSelectedTEMaterial::getSpecularRotation(spec_rotation,identical_spec_rotation); + LLSelectedTEMaterial::getNormalRotation(norm_rotation,identical_norm_rotation); + + bool diff_rot_tentative = !(align_planar ? identical_planar_aligned : identical_diff_rotation); + bool norm_rot_tentative = !(align_planar ? identical_planar_aligned : identical_norm_rotation); + bool spec_rot_tentative = !(align_planar ? identical_planar_aligned : identical_spec_rotation); + + F32 diff_rot_deg = diff_rotation * RAD_TO_DEG; + F32 norm_rot_deg = norm_rotation * RAD_TO_DEG; + F32 spec_rot_deg = spec_rotation * RAD_TO_DEG; + + // TODO: do we need to enable/disable all these manually anymore? -Zi + /* + mCtrlTexRot->setEnabled(editable && has_material); + + mCtrlShinyRot->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls); + mCtrlBumpyRot->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls); + */ + + mCtrlTexRot->setTentative(diff_rot_tentative); + mCtrlBumpyRot->setTentative(LLSD(norm_rot_tentative)); + mCtrlShinyRot->setTentative(LLSD(spec_rot_tentative)); + + mCtrlTexRot->setValue( editable ? diff_rot_deg : 0.0f); + mCtrlShinyRot->setValue(editable ? spec_rot_deg : 0.0f); + mCtrlBumpyRot->setValue(editable ? norm_rot_deg : 0.0f); + } + + { + F32 glow = 0.f; + bool identical_glow = false; + LLSelectedTE::getGlow(glow,identical_glow); + + mCtrlGlow->setValue(glow); + mCtrlGlow->setTentative(!identical_glow); + mCtrlGlow->setEnabled(editable); + } + + { + // Maps from enum to combobox entry index + mComboTexGen->selectNthItem(((S32)selected_texgen) >> 1); + + mComboTexGen->setEnabled(editable); + mComboTexGen->setTentative(!identical); + mLabelTexGen->setEnabled(editable); + } + + { + U8 fullbright_flag = 0; + bool identical_fullbright = false; + + LLSelectedTE::getFullbright(fullbright_flag,identical_fullbright); + + mCheckFullbright->setValue((S32)(fullbright_flag != 0)); + mCheckFullbright->setEnabled(editable ); + mCheckFullbright->setTentative(!identical_fullbright); + + // TODO: find a better way to do this without relying on the name -Zi + childSetEnabled("panel_material_type_media", !has_pbr_material); + LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_material_type_media " << !has_pbr_material << LL_ENDL; + } + + // Repeats per meter + { + F32 repeats_diff = 1.f; + F32 repeats_norm = 1.f; + F32 repeats_spec = 1.f; + + bool identical_diff_repeats = false; + bool identical_norm_repeats = false; + bool identical_spec_repeats = false; + + LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats); + LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats); + LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats); + + S32 index = mComboTexGen->getCurrentIndex(); + bool enabled = editable && (index != 1); + bool identical_repeats = true; + + S32 material_selection = getCurrentMaterialType(); + F32 repeats = 1.0f; + + U32 material_type = MATTYPE_DIFFUSE; + if (material_selection == MATMEDIA_MATERIAL) + { + material_type = getCurrentMatChannel(); + } + // TODO: check if repeats per meter even apply to PBR materials -Zi + else if (material_selection == MATMEDIA_PBR) + { + enabled = editable; + material_type = getCurrentPBRChannel(); + } + + switch (material_type) + { + default: + case MATTYPE_DIFFUSE: + { + if (material_selection != MATMEDIA_PBR) + { + enabled = editable && !id.isNull(); + } + identical_repeats = identical_diff_repeats; + repeats = repeats_diff; + } + break; + + case MATTYPE_SPECULAR: + { + if (material_selection != MATMEDIA_PBR) + { + enabled = (editable && ((shiny == SHINY_TEXTURE) && !specmap_id.isNull()) + && enable_material_controls); // Materials Alignment + } + identical_repeats = identical_spec_repeats; + repeats = repeats_spec; + } + break; + + case MATTYPE_NORMAL: + { + if (material_selection != MATMEDIA_PBR) + { + enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull()) + && enable_material_controls); // Materials Alignment + } + identical_repeats = identical_norm_repeats; + repeats = repeats_norm; + } + break; + } + + bool repeats_tentative = !identical_repeats; + + if (force_set_values) + { + //onCommit, previosly edited element updates related ones + mCtrlRpt->forceSetValue(editable ? repeats : 1.0f); + } + else + { + mCtrlRpt->setValue(editable ? repeats : 1.0f); + } + mCtrlRpt->setTentative(LLSD(repeats_tentative)); + mCtrlRpt->setEnabled(!identical_planar_texgen && enabled); + } + + // Blinn-Phong Materials + { + LLMaterialPtr material; + LLSelectedTEMaterial::getCurrent(material, identical); + + mComboShininess->setTentative(!identical_spec); + mCtrlGlossiness->setTentative(!identical_spec); + mCtrlEnvironment->setTentative(!identical_spec); + mShinyColorSwatch->setTentative(!identical_spec); + + if (material && editable) + { + LL_DEBUGS("Materials") << material->asLLSD() << LL_ENDL; + + // Alpha + U32 alpha_mode = material->getDiffuseAlphaMode(); + + if (transparency > 0.f) + { //it is invalid to have any alpha mode other than blend if transparency is greater than zero ... + alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; + } + + if (!mIsAlpha) + { // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none + alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + } + + mComboAlphaMode->selectNthItem(alpha_mode); + + mCtrlMaskCutoff->setValue(material->getAlphaMaskCutoff()); + + updateAlphaControls(); + + identical_planar_texgen = isIdenticalPlanarTexgen(); + + // Shiny (specular) + F32 offset_x, offset_y, repeat_x, repeat_y, rot; + + mShinyTextureCtrl->setImageAssetID(material->getSpecularID()); + + if (material->getSpecularID().notNull() && (shiny == SHINY_TEXTURE)) + { + material->getSpecularOffset(offset_x,offset_y); + material->getSpecularRepeat(repeat_x,repeat_y); + + if (identical_planar_texgen) + { + repeat_x *= 2.0f; + repeat_y *= 2.0f; + } + + rot = material->getSpecularRotation(); + mCtrlShinyScaleU->setValue(repeat_x); + mCtrlShinyScaleV->setValue(repeat_y); + mCtrlShinyRot->setValue(rot*RAD_TO_DEG); + mCtrlShinyOffsetU->setValue(offset_x); + mCtrlShinyOffsetV->setValue(offset_y); + mCtrlGlossiness->setValue(material->getSpecularLightExponent()); + mCtrlEnvironment->setValue(material->getEnvironmentIntensity()); + + updateShinyControls(!material->getSpecularID().isNull(), true); + } + + // Assert desired colorswatch color to match material AFTER updateShinyControls + // to avoid getting overwritten with the default on some UI state changes. + // + if (material->getSpecularID().notNull()) + { + LLColor4 new_color = material->getSpecularLightColor(); + LLColor4 old_color = mShinyColorSwatch->get(); + + mShinyColorSwatch->setOriginal(new_color); + mShinyColorSwatch->set(new_color, force_set_values || old_color != new_color || !editable); + } + + // Bumpy (normal) + mBumpyTextureCtrl->setImageAssetID(material->getNormalID()); + + if (material->getNormalID().notNull()) + { + material->getNormalOffset(offset_x,offset_y); + material->getNormalRepeat(repeat_x,repeat_y); + + if (identical_planar_texgen) + { + repeat_x *= 2.0f; + repeat_y *= 2.0f; + } + + rot = material->getNormalRotation(); + mCtrlBumpyScaleU->setValue(repeat_x); + mCtrlBumpyScaleV->setValue(repeat_y); + mCtrlBumpyRot->setValue(rot*RAD_TO_DEG); + mCtrlBumpyOffsetU->setValue(offset_x); + mCtrlBumpyOffsetV->setValue(offset_y); + + updateBumpyControls(!material->getNormalID().isNull(), true); + } + } + } + + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + bool single_volume = (selected_count == 1); + mBtnCopyFaces->setEnabled(editable && single_volume); + mBtnPasteFaces->setEnabled(editable && !mClipboardParams.emptyMap() && (mClipboardParams.has("color") || mClipboardParams.has("texture"))); + + // Set variable values for numeric expressions + LLCalc* calcp = LLCalc::getInstance(); + calcp->setVar(LLCalc::TEX_U_SCALE, getCurrentTextureScaleU()); + calcp->setVar(LLCalc::TEX_V_SCALE, getCurrentTextureScaleV()); + calcp->setVar(LLCalc::TEX_U_OFFSET, getCurrentTextureOffsetU()); + calcp->setVar(LLCalc::TEX_V_OFFSET, getCurrentTextureOffsetV()); + calcp->setVar(LLCalc::TEX_ROTATION, getCurrentTextureRot()); + calcp->setVar(LLCalc::TEX_TRANSPARENCY, mCtrlColorTransp->getValue().asReal()); + calcp->setVar(LLCalc::TEX_GLOW, mCtrlGlow->getValue().asReal()); + + // Find all faces with same texture + // TODO: these were not yet added to the new texture panel -Zi + /* + getChild("btn_select_same_diff")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mTextureCtrl->getEnabled()); + getChild("btn_select_same_norm")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mBumpyTextureCtrl->getEnabled()); + getChild("btn_select_same_spec")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mShinyTextureCtrl->getEnabled()); + */ + } + else + { + // we can not edit this object's faces or there is no object selected, so + // we can just as well blank out the whole thing. -Zi + gSavedSettings.setBOOL("FSInternalCanEditObjectFaces", false); + LL_DEBUGS("ENABLEDISABLETOOLS") << "hide face edit controls" << LL_ENDL; + } +} + +// One-off listener that updates the build floater UI when the agent inventory adds or removes an item +// TODO: CHECK - Why do we even have this? -Zi +class PBRPickerAgentListener : public LLInventoryObserver +{ +protected: + bool mChangePending = true; +public: + PBRPickerAgentListener() : LLInventoryObserver() + { + gInventory.addObserver(this); + } + + const bool isListening() + { + return mChangePending; + } + + void changed(U32 mask) override + { + if (!(mask & (ADD | REMOVE))) + { + return; + } + + if (gFloaterTools) + { + gFloaterTools->dirty(); + } + gInventory.removeObserver(this); + mChangePending = false; + } + + ~PBRPickerAgentListener() override + { + gInventory.removeObserver(this); + mChangePending = false; + } +}; + +// One-off listener that updates the build floater UI when the prim inventory updates +// TODO: CHECK - Why do we even have this? -Zi +class PBRPickerObjectListener : public LLVOInventoryListener +{ + protected: + LLViewerObject* mObjectp; + bool mChangePending = true; + + public: + PBRPickerObjectListener(LLViewerObject* object) + : mObjectp(object) + { + registerVOInventoryListener(mObjectp, nullptr); + } + + const bool isListeningFor(const LLViewerObject* objectp) const + { + return mChangePending && (objectp == mObjectp); + } + + void inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data) override + { + if (gFloaterTools) + { + gFloaterTools->dirty(); + } + removeVOInventoryListener(); + mChangePending = false; + } + + ~PBRPickerObjectListener() + { + removeVOInventoryListener(); + mChangePending = false; + } +}; + +void FSPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values) +{ + const bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable(); + + mTabsPBRMatMedia->enableTabButton( + mTabsPBRMatMedia->getIndexForPanel( + mTabsPBRMatMedia->getPanelByName("panel_material_type_pbr")), has_pbr_capabilities); + LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_material_type_pbr " << has_pbr_capabilities << LL_ENDL; + + LLSelectedTEGetmatId func; + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func); + + has_pbr_material = func.mHasFacesWithPBR; + has_faces_without_pbr = func.mHasFacesWithoutPBR; + + // this could just be saved in the class instead of fetching it again after updateUI() already did -Zi + const bool settable = has_pbr_capabilities && objectp->permModify() && !objectp->isPermanentEnforced(); // do not depend on non-PBR here so we can turn any face into PBR -Zi + const bool editable = LLMaterialEditor::canModifyObjectsMaterial() && !has_faces_without_pbr; + const bool saveable = LLMaterialEditor::canSaveObjectsMaterial() && !has_faces_without_pbr; + + mMaterialCtrlPBR->setEnabled(settable); + mMaterialCtrlPBR->setTentative(!func.mIdenticalMaterial); + mMaterialCtrlPBR->setImageAssetID(func.mMaterialId); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mMaterialCtrlPBR " << settable << LL_ENDL; + + LL_DEBUGS("ENABLEDISABLETOOLS") << "PBR controls overall: " << editable << LL_ENDL; + + mBaseTexturePBR->setEnabled(editable); + mBaseTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] : LLUUID::null); + mBaseTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); + + mBaseTintPBR->setEnabled(editable); + + mBaseTintPBR->set(srgbColor4(func.mMaterialSummary.mBaseColor)); + mBaseTintPBR->setTentative(!func.mIdenticalBaseColor); // TODO: split alpha from color? -Zi + mBaseTintPBR->setValid(editable); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mBaseTintPBR valid " << editable << LL_ENDL; + mBaseTintPBR->setFallbackImage(LLUI::getUIImage("locked_image.j2c") ); + + mNormalTexturePBR->setEnabled(editable); + mNormalTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] : LLUUID::null); + mNormalTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]); + + mORMTexturePBR->setEnabled(editable); + mORMTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] : LLUUID::null); + mORMTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]); + + mEmissiveTexturePBR->setEnabled(editable); + mEmissiveTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] : LLUUID::null); + mEmissiveTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]); + + mEmissiveTintPBR->setEnabled(editable); + mEmissiveTintPBR->set(srgbColor4(func.mMaterialSummary.mEmissiveColor)); + mEmissiveTintPBR->setTentative(!func.mIdenticalEmissive); + mEmissiveTintPBR->setValid(editable); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mEmissiveTintPBR valid " << editable << LL_ENDL; + mEmissiveTintPBR->setFallbackImage(LLUI::getUIImage("locked_image.j2c") ); + + mCheckDoubleSidedPBR->setEnabled(editable); + mCheckDoubleSidedPBR->setValue(func.mMaterialSummary.mDoubleSided); + mCheckDoubleSidedPBR->setTentative(!func.mIdenticalDoubleSided); + + mAlphaPBR->setEnabled(editable); + mAlphaPBR->setValue(func.mMaterialSummary.mBaseColor.mV[VALPHA]); + mAlphaPBR->setTentative(!func.mIdenticalBaseColor); // TODO: split alpha from color? -Zi + + mAlphaModePBR->setEnabled(editable); + mAlphaModePBR->setValue(func.mMaterialSummary.getAlphaMode()); + mAlphaModePBR->setTentative(!func.mIdenticalAlphaMode); + mLabelAlphaModePBR->setEnabled(editable); + + mMaskCutoffPBR->setEnabled(editable); + mMaskCutoffPBR->setValue(func.mMaterialSummary.mAlphaCutoff); + mMaskCutoffPBR->setTentative(!func.mIdenticalAlphaCutoff); + + mMetallicFactorPBR->setEnabled(editable); + mMetallicFactorPBR->setValue(func.mMaterialSummary.mMetallicFactor); + mMetallicFactorPBR->setTentative(!func.mIdenticalMetallic); + + mRoughnessFactorPBR->setEnabled(editable); + mRoughnessFactorPBR->setValue(func.mMaterialSummary.mRoughnessFactor); + mRoughnessFactorPBR->setTentative(!func.mIdenticalRoughness); + + if (func.mMaterial) + { + mPBRBaseMaterialParams.mMap = func.mMaterial->mTextureId; + mPBRBaseMaterialParams.mBaseColorTint = srgbColor4(func.mMaterial->mBaseColor); + mPBRBaseMaterialParams.mMetallic = func.mMaterial->mMetallicFactor; + mPBRBaseMaterialParams.mRoughness = func.mMaterial->mRoughnessFactor; + mPBRBaseMaterialParams.mEmissiveTint = func.mMaterial->mEmissiveColor; + mPBRBaseMaterialParams.mAlphaMode = func.mMaterial->mAlphaMode; + mPBRBaseMaterialParams.mAlphaCutoff = func.mMaterial->mAlphaCutoff; + mPBRBaseMaterialParams.mDoubleSided = func.mMaterial->mDoubleSided; + } + + if (objectp->isAttachment()) + { + // TODO: coming in from latest patch, seems broken? + mMaterialCtrlPBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); + // TODO: before: + // mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER | PERM_MODIFY); + } + else + { + mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_NONE); + } + + mBtnSavePBR->setEnabled(saveable); // TODO: flag for "something is not identical" -Zi && pbr_identical); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mBtnSavePBR " << saveable << LL_ENDL; + + // TODO: CHECK - Find out if we need this at all -Zi + if (objectp->isInventoryPending()) + { + // Reuse the same listener when possible + if (!mVOInventoryListener || !mVOInventoryListener->isListeningFor(objectp)) + { + mVOInventoryListener = std::make_unique(objectp); + } + } + else + { + mVOInventoryListener = nullptr; + } + if (!func.mIdenticalMaterial || func.mMaterialId.isNull() || func.mMaterialId == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID) + { + mAgentInventoryListener = nullptr; + } + else + { + if (!mAgentInventoryListener || !mAgentInventoryListener->isListening()) + { + mAgentInventoryListener = std::make_unique(); + } + } + + // Control values will be set once per frame in setMaterialOverridesFromSelection + sMaterialOverrideSelection.setDirty(); +} + +void FSPanelFace::updateCopyTexButton() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + mBtnCopyFaces->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify() + && !objectp->isPermanentEnforced() && !objectp->isInventoryPending() + && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1) + && LLMaterialEditor::canClipboardObjectsMaterial()); + std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options"); + mBtnCopyFaces->setToolTip(tooltip); +} + +void FSPanelFace::refresh() +{ + LL_DEBUGS("Materials") << LL_ENDL; + getState(); +} + +void FSPanelFace::refreshMedia() +{ + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* first_object = selected_objects->getFirstObject(); + + if (!(first_object + && first_object->getPCode() == LL_PCODE_VOLUME + && first_object->permModify() + )) + { + mBtnAddMedia->setEnabled(false); + mTitleMediaText->clear(); + clearMediaSettings(); + return; + } + + std::string url = first_object->getRegion()->getCapability("ObjectMedia"); + bool has_media_capability = (!url.empty()); + + if (!has_media_capability) + { + mBtnAddMedia->setEnabled(false); + LL_WARNS("LLFloaterToolsMedia") << "Media not enabled (no capability) in this region!" << LL_ENDL; + clearMediaSettings(); + return; + } + + bool is_nonpermanent_enforced = (LLSelectMgr::getInstance()->getSelection()->getFirstRootNode() + && LLSelectMgr::getInstance()->selectGetRootsNonPermanentEnforced()) + || LLSelectMgr::getInstance()->selectGetNonPermanentEnforced(); + bool editable = is_nonpermanent_enforced && (first_object->permModify() || selectedMediaEditable()); + + // Check modify permissions and whether any selected objects are in + // the process of being fetched. If they are, then we're not editable + if (editable) + { + LLObjectSelection::iterator iter = selected_objects->begin(); + LLObjectSelection::iterator end = selected_objects->end(); + for (; iter != end; ++iter) + { + LLSelectNode* node = *iter; + LLVOVolume* object = dynamic_cast(node->getObject()); + if (object && !object->permModify()) + { + LL_INFOS("LLFloaterToolsMedia") + << "Selection not editable due to lack of modify permissions on object id " + << object->getID() << LL_ENDL; + + editable = false; + break; + } + } + } + + // Media settings + bool bool_has_media = false; + struct media_functor : public LLSelectedTEGetFunctor + { + bool get(LLViewerObject* object, S32 face) + { + LLTextureEntry *te = object->getTE(face); + if (te) + { + return te->hasMedia(); + } + return false; + } + } func; + + // check if all faces have media (or, all don't have media) + LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue(&func, bool_has_media); + + const LLMediaEntry default_media_data; + + struct functor_getter_media_data : public LLSelectedTEGetFunctor< LLMediaEntry> + { + functor_getter_media_data(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + LLMediaEntry get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return *(object->getTE(face)->getMediaData()); + } + return mMediaEntry; + }; + + const LLMediaEntry& mMediaEntry; + + } func_media_data(default_media_data); + + LLMediaEntry media_data_get; + LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get)); + + std::string multi_media_info_str = LLTrans::getString("Multiple Media"); + std::string media_title = ""; + + // update UI depending on whether "object" (prim or face) has media + // and whether or not you are allowed to edit it. + + mBtnAddMedia->setEnabled(editable); + + // IF all the faces have media (or all don't have media) + if (LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo) + { + // TODO: get media title and set it. + mTitleMediaText->clear(); + + // if identical is set, all faces are same (whether all empty or has the same media) + if (!(LLFloaterMediaSettings::getInstance()->mMultipleMedia)) + { + // media data is valid + if (media_data_get != default_media_data) + { + // initial media title is the media URL (until we get the name) + media_title = media_data_get.getHomeURL(); + } + // else all faces might be empty + } + else // there are Different media been set on on the faces + { + media_title = multi_media_info_str; + } + + mBtnDeleteMedia->setEnabled(bool_has_media && editable); + + // TODO: display a list of all media on the face - use 'identical' flag + } + else // not all faces have media but at least one does + { + // selected faces have not identical value + LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data); + + if (LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + media_title = multi_media_info_str; + } + else + { + // Media data is valid + if (media_data_get != default_media_data) + { + // initial media title is the media URL (until we get the name) + media_title = media_data_get.getHomeURL(); + } + } + + mBtnDeleteMedia->setEnabled(TRUE); + } + + S32 materials_media = getCurrentMaterialType(); + if (materials_media == MATMEDIA_MEDIA) + { + // currently displaying media info, navigateTo and update title + navigateToTitleMedia(media_title); + } + else + { + // Media can be heavy, don't keep it around + // MAC specific: MAC doesn't support setVolume(0) so if not + // unloaded, it might keep playing audio until user closes editor + unloadMedia(); + mNeedMediaTitle = false; + } + + mTitleMediaText->setText(media_title); + + // load values for media settings + updateMediaSettings(); + + LLFloaterMediaSettings::initValues(mMediaSettings, editable); +} + +void FSPanelFace::unloadMedia() +{ + // destroy media source used to grab media title + mTitleMedia->unloadMediaSource(); +} + +void FSPanelFace::onMaterialOverrideReceived(const LLUUID& object_id, S32 side) +{ + sMaterialOverrideSelection.onSelectedObjectUpdated(object_id, side); +} + +////////////////////////////////////////////////////////////////////////////// +// +void FSPanelFace::navigateToTitleMedia(const std::string url) +{ + std::string multi_media_info_str = LLTrans::getString("Multiple Media"); + if (url.empty() || multi_media_info_str == url) + { + // nothing to show + mNeedMediaTitle = false; + } + else + { + LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin(); + + // check if url changed or if we need a new media source + if (mTitleMedia->getCurrentNavUrl() != url || media_plugin == nullptr) + { + mTitleMedia->navigateTo(url); + + LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mTitleMedia->getTextureID()); + if (impl) + { + // if it's a page with a movie, we don't want to hear it + impl->setVolume(0); + } + } + + // flag that we need to update the title (even if no request were made) + mNeedMediaTitle = true; + } +} + +bool FSPanelFace::selectedMediaEditable() +{ + U32 owner_mask_on; + U32 owner_mask_off; + U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER, + &owner_mask_on, &owner_mask_off); + U32 group_mask_on; + U32 group_mask_off; + U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_GROUP, + &group_mask_on, &group_mask_off); + U32 everyone_mask_on; + U32 everyone_mask_off; + S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_EVERYONE, + &everyone_mask_on, &everyone_mask_off); + + bool selected_Media_editable = false; + + // if perms we got back are valid + if (valid_owner_perms && + valid_group_perms && + valid_everyone_perms) + { + if ((owner_mask_on & PERM_MODIFY) || + (group_mask_on & PERM_MODIFY) || + (everyone_mask_on & PERM_MODIFY)) + { + selected_Media_editable = true; + } + else + { + // user is NOT allowed to press the RESET button + selected_Media_editable = false; + }; + }; + + return selected_Media_editable; +} + +void FSPanelFace::clearMediaSettings() +{ + LLFloaterMediaSettings::clearValues(false); +} + +void FSPanelFace::updateMediaSettings() +{ + bool identical(false); + std::string base_key(""); + std::string value_str(""); + int value_int = 0; + bool value_bool = false; + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + // TODO: (CP) refactor this using something clever or boost or both !! + + const LLMediaEntry default_media_data; + + // controls + U8 value_u8 = default_media_data.getControls(); + struct functor_getter_controls : public LLSelectedTEGetFunctor + { + functor_getter_controls(const LLMediaEntry &entry) : mMediaEntry(entry) {} + + U8 get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getControls(); + } + return mMediaEntry.getControls(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_controls(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_controls, value_u8); + base_key = std::string(LLMediaEntry::CONTROLS_KEY); + mMediaSettings[base_key] = value_u8; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // First click (formerly left click) + value_bool = default_media_data.getFirstClickInteract(); + struct functor_getter_first_click : public LLSelectedTEGetFunctor + { + functor_getter_first_click(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getFirstClickInteract(); + } + return mMediaEntry.getFirstClickInteract(); + }; + + const LLMediaEntry &mMediaEntry; + } func_first_click(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_first_click, value_bool); + base_key = std::string(LLMediaEntry::FIRST_CLICK_INTERACT_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Home URL + value_str = default_media_data.getHomeURL(); + struct functor_getter_home_url : public LLSelectedTEGetFunctor + { + functor_getter_home_url(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + std::string get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getHomeURL(); + } + return mMediaEntry.getHomeURL(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_home_url(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_home_url, value_str); + base_key = std::string(LLMediaEntry::HOME_URL_KEY); + mMediaSettings[base_key] = value_str; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Current URL + value_str = default_media_data.getCurrentURL(); + struct functor_getter_current_url : public LLSelectedTEGetFunctor + { + functor_getter_current_url(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + std::string get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getCurrentURL(); + } + return mMediaEntry.getCurrentURL(); + }; + + const LLMediaEntry &mMediaEntry; + } func_current_url(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_current_url, value_str); + base_key = std::string(LLMediaEntry::CURRENT_URL_KEY); + mMediaSettings[base_key] = value_str; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Auto zoom + value_bool = default_media_data.getAutoZoom(); + struct functor_getter_auto_zoom : public LLSelectedTEGetFunctor + { + functor_getter_auto_zoom(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAutoZoom(); + } + return mMediaEntry.getAutoZoom(); + }; + + const LLMediaEntry &mMediaEntry; + } func_auto_zoom(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_auto_zoom, value_bool); + base_key = std::string(LLMediaEntry::AUTO_ZOOM_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Auto play + //value_bool = default_media_data.getAutoPlay(); + // set default to auto play TRUE -- angela EXT-5172 + value_bool = true; + struct functor_getter_auto_play : public LLSelectedTEGetFunctor + { + functor_getter_auto_play(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAutoPlay(); + } + //return mMediaEntry.getAutoPlay(); set default to auto play TRUE -- angela EXT-5172 + return true; + }; + + const LLMediaEntry &mMediaEntry; + + } func_auto_play(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_auto_play, value_bool); + base_key = std::string(LLMediaEntry::AUTO_PLAY_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + + // Auto scale + // set default to auto scale TRUE -- angela EXT-5172 + //value_bool = default_media_data.getAutoScale(); + value_bool = true; + struct functor_getter_auto_scale : public LLSelectedTEGetFunctor + { + functor_getter_auto_scale(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAutoScale(); + } + // return mMediaEntry.getAutoScale(); set default to auto scale TRUE -- angela EXT-5172 + return true; + }; + + const LLMediaEntry &mMediaEntry; + + } func_auto_scale(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_auto_scale, value_bool); + base_key = std::string(LLMediaEntry::AUTO_SCALE_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Auto loop + value_bool = default_media_data.getAutoLoop(); + struct functor_getter_auto_loop : public LLSelectedTEGetFunctor + { + functor_getter_auto_loop(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAutoLoop(); + } + return mMediaEntry.getAutoLoop(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_auto_loop(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_auto_loop, value_bool); + base_key = std::string(LLMediaEntry::AUTO_LOOP_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // width pixels (if not auto scaled) + value_int = default_media_data.getWidthPixels(); + struct functor_getter_width_pixels : public LLSelectedTEGetFunctor + { + functor_getter_width_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + int get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getWidthPixels(); + } + return mMediaEntry.getWidthPixels(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_width_pixels(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_width_pixels, value_int); + base_key = std::string(LLMediaEntry::WIDTH_PIXELS_KEY); + mMediaSettings[base_key] = value_int; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // height pixels (if not auto scaled) + value_int = default_media_data.getHeightPixels(); + struct functor_getter_height_pixels : public LLSelectedTEGetFunctor + { + functor_getter_height_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + int get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getHeightPixels(); + } + return mMediaEntry.getHeightPixels(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_height_pixels(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_height_pixels, value_int); + base_key = std::string(LLMediaEntry::HEIGHT_PIXELS_KEY); + mMediaSettings[base_key] = value_int; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Enable Alt image + value_bool = default_media_data.getAltImageEnable(); + struct functor_getter_enable_alt_image : public LLSelectedTEGetFunctor + { + functor_getter_enable_alt_image(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getAltImageEnable(); + } + return mMediaEntry.getAltImageEnable(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_enable_alt_image(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_enable_alt_image, value_bool); + base_key = std::string(LLMediaEntry::ALT_IMAGE_ENABLE_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - owner interact + value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER); + struct functor_getter_perms_owner_interact : public LLSelectedTEGetFunctor + { + functor_getter_perms_owner_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_OWNER)); + } + return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_OWNER); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_owner_interact(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_owner_interact, value_bool); + base_key = std::string(LLPanelContents::PERMS_OWNER_INTERACT_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - owner control + value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER); + struct functor_getter_perms_owner_control : public LLSelectedTEGetFunctor + { + functor_getter_perms_owner_control(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_OWNER)); + } + return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_OWNER); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_owner_control(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_owner_control, value_bool); + base_key = std::string(LLPanelContents::PERMS_OWNER_CONTROL_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - group interact + value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP); + struct functor_getter_perms_group_interact : public LLSelectedTEGetFunctor + { + functor_getter_perms_group_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_GROUP)); + } + return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_GROUP); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_group_interact(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_group_interact, value_bool); + base_key = std::string(LLPanelContents::PERMS_GROUP_INTERACT_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - group control + value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP); + struct functor_getter_perms_group_control : public LLSelectedTEGetFunctor + { + functor_getter_perms_group_control(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_GROUP)); + } + return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_GROUP); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_group_control(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_group_control, value_bool); + base_key = std::string(LLPanelContents::PERMS_GROUP_CONTROL_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - anyone interact + value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE); + struct functor_getter_perms_anyone_interact : public LLSelectedTEGetFunctor + { + functor_getter_perms_anyone_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_ANYONE)); + } + return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_ANYONE); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_anyone_interact(default_media_data); + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func_perms_anyone_interact, value_bool); + base_key = std::string(LLPanelContents::PERMS_ANYONE_INTERACT_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // Perms - anyone control + value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE); + struct functor_getter_perms_anyone_control : public LLSelectedTEGetFunctor + { + functor_getter_perms_anyone_control(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_ANYONE)); + } + return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_ANYONE); + }; + + const LLMediaEntry &mMediaEntry; + + } func_perms_anyone_control(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_perms_anyone_control, value_bool); + base_key = std::string(LLPanelContents::PERMS_ANYONE_CONTROL_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // security - whitelist enable + value_bool = default_media_data.getWhiteListEnable(); + struct functor_getter_whitelist_enable : public LLSelectedTEGetFunctor + { + functor_getter_whitelist_enable(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + bool get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getWhiteListEnable(); + } + return mMediaEntry.getWhiteListEnable(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_whitelist_enable(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_whitelist_enable, value_bool); + base_key = std::string(LLMediaEntry::WHITELIST_ENABLE_KEY); + mMediaSettings[base_key] = value_bool; + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; + + // security - whitelist URLs + std::vector value_vector_str = default_media_data.getWhiteList(); + struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor> + { + functor_getter_whitelist_urls(const LLMediaEntry& entry) : mMediaEntry(entry) {} + + std::vector get(LLViewerObject* object, S32 face) + { + if (object && object->getTE(face) && object->getTE(face)->getMediaData()) + { + return object->getTE(face)->getMediaData()->getWhiteList(); + } + return mMediaEntry.getWhiteList(); + }; + + const LLMediaEntry &mMediaEntry; + + } func_whitelist_urls(default_media_data); + + identical = selected_objects->getSelectedTEValue(&func_whitelist_urls, value_vector_str); + base_key = std::string(LLMediaEntry::WHITELIST_KEY); + mMediaSettings[base_key].clear(); + + std::vector< std::string >::iterator iter = value_vector_str.begin(); + while (iter != value_vector_str.end()) + { + std::string white_list_url = *iter; + mMediaSettings[base_key].append(white_list_url); + ++iter; + }; + + mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical; +} + +void FSPanelFace::updateMediaTitle() +{ + // only get the media name if we need it + if (!mNeedMediaTitle) + { + return; + } + + // get plugin impl + LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin(); + if (media_plugin && mTitleMedia->getCurrentNavUrl() == media_plugin->getNavigateURI()) + { + // get the media name (asynchronous - must call repeatedly) + std::string media_title = media_plugin->getMediaName(); + + // only replace the title if what we get contains something + if (!media_title.empty()) + { + // update the UI widget + mTitleMediaText->setText(media_title); + + // stop looking for a title when we get one + mNeedMediaTitle = false; + } + } +} + +void FSPanelFace::onCommitColor() +{ + sendColor(); +} + +void FSPanelFace::onCommitShinyColor() +{ + LLSelectedTEMaterial::setSpecularLightColor(this, mShinyColorSwatch->get()); +} + +void FSPanelFace::onCommitAlpha() +{ + sendAlpha(); +} + +void FSPanelFace::onCancelColor() +{ + LLSelectMgr::getInstance()->selectionRevertColors(); +} + +void FSPanelFace::onCancelShinyColor() +{ + LLSelectMgr::getInstance()->selectionRevertShinyColors(); +} + +void FSPanelFace::onSelectColor() +{ + LLSelectMgr::getInstance()->saveSelectedObjectColors(); + sendColor(); +} + +void FSPanelFace::onSelectShinyColor() +{ + LLSelectedTEMaterial::setSpecularLightColor(this, mShinyColorSwatch->get()); + LLSelectMgr::getInstance()->saveSelectedShinyColors(); +} + +void FSPanelFace::updateVisibility(LLViewerObject* objectp /* = nullptr */) +{ + updateAlphaControls(); + // TODO: is this still needed? -Zi + updateShinyControls(); + updateBumpyControls(); + + // Find all faces with same texture + // TODO: is this still needed? -Zi Probably not but we don't have these buttons yet anyway -Zi + /* + getChild("btn_select_same_diff")->setVisible(mTextureCtrl->getVisible()); + getChild("btn_select_same_norm")->setVisible(mBumpyTextureCtrl->getVisible()); + getChild("btn_select_same_spec")->setVisible(mShinyTextureCtrl->getVisible()); + */ +} + +void FSPanelFace::onCommitBump() +{ + sendBump(mComboBumpiness->getCurrentIndex()); +} + +void FSPanelFace::onCommitTexGen() +{ + sendTexGen(); +} + +void FSPanelFace::updateShinyControls(bool is_setting_texture, bool mess_with_shiny_combobox) +{ + LLUUID shiny_texture_ID = mShinyTextureCtrl->getImageAssetID(); + LL_DEBUGS("Materials") << "Shiny texture selected: " << shiny_texture_ID << LL_ENDL; + + if(mess_with_shiny_combobox) + { + if (shiny_texture_ID.notNull() && is_setting_texture) + { + if (!mComboShininess->itemExists(USE_TEXTURE_LABEL)) + { + mComboShininess->add(USE_TEXTURE_LABEL); + } + mComboShininess->setSimple(USE_TEXTURE_LABEL); + } + else + { + if (mComboShininess->itemExists(USE_TEXTURE_LABEL)) + { + mComboShininess->remove(SHINY_TEXTURE); + mComboShininess->selectFirstItem(); + } + } + } + else + { + if (shiny_texture_ID.isNull() && mComboShininess->itemExists(USE_TEXTURE_LABEL)) + { + mComboShininess->remove(SHINY_TEXTURE); + mComboShininess->selectFirstItem(); + } + } + + mShinyColorSwatch->setValid(shiny_texture_ID.notNull()); + LL_DEBUGS("ENABLEDISABLETOOLS") << "mShinyColorSwatch valid " << shiny_texture_ID.notNull() << LL_ENDL; + mShinyColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c")); + + gSavedSettings.setBOOL("FSInternalFaceHasBPSpecularMap", shiny_texture_ID.notNull()); + + LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_blinn_phong_specular " << shiny_texture_ID.notNull() << LL_ENDL; +} + +void FSPanelFace::updateBumpyControls(bool is_setting_texture, bool mess_with_combobox) +{ + LLUUID bumpy_texture_ID = mBumpyTextureCtrl->getImageAssetID(); + LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL; + + if (mess_with_combobox) + { + LLUUID bumpy_texture_ID = mBumpyTextureCtrl->getImageAssetID(); + LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL; + + if (bumpy_texture_ID.notNull() && is_setting_texture) + { + if (!mComboBumpiness->itemExists(USE_TEXTURE_LABEL)) + { + mComboBumpiness->add(USE_TEXTURE_LABEL); + } + mComboBumpiness->setSimple(USE_TEXTURE_LABEL); + } + else + { + if (mComboBumpiness->itemExists(USE_TEXTURE_LABEL)) + { + mComboBumpiness->remove(BUMPY_TEXTURE); + mComboBumpiness->selectFirstItem(); + } + } + } + + gSavedSettings.setBOOL("FSInternalFaceHasBPNormalMap", bumpy_texture_ID.notNull()); + + LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_blinn_phong_normal " << bumpy_texture_ID.notNull() << LL_ENDL; +} + +void FSPanelFace::onCommitShiny() +{ + sendShiny(mComboShininess->getCurrentIndex()); +} + +void FSPanelFace::updateAlphaControls() +{ + mCtrlMaskCutoff->setEnabled(getCurrentDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK); +} + +void FSPanelFace::onCommitAlphaMode() +{ + updateAlphaControls(); + LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode()); +} + +void FSPanelFace::onCommitFullbright() +{ + sendFullbright(); +} + +void FSPanelFace::onCommitGlow() +{ + sendGlow(); +} + +// +// PBR +// + +// Get a dump of the json representation of the current state of the editor UI +// in GLTF format, excluding transforms as they are not supported in material +// assets. (See also LLGLTFMaterial::sanitizeAssetMaterial()) +void FSPanelFace::getGLTFMaterial(LLGLTFMaterial* mat) +{ + mat->mBaseColor = linearColor4(LLColor4(mBaseTintPBR->get())); + mat->mBaseColor.mV[VALPHA] = mAlphaPBR->get(); + + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = mBaseTexturePBR->getImageAssetID(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = mNormalTexturePBR->getImageAssetID(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = mORMTexturePBR->getImageAssetID(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = mEmissiveTexturePBR->getImageAssetID(); + + mat->mEmissiveColor = linearColor4(LLColor4(mEmissiveTintPBR->get())); + + mat->mMetallicFactor = mMetallicFactorPBR->get(); + mat->mRoughnessFactor = mRoughnessFactorPBR->get(); + + mat->mDoubleSided = mCheckDoubleSidedPBR->get(); + mat->setAlphaMode(mAlphaModePBR->getValue().asString()); + mat->mAlphaCutoff = mMaskCutoffPBR->getValue().asReal(); +} + +BOOL FSPanelFace::onDragPbr(LLInventoryItem* item) +{ + bool accept = true; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if (!LLToolDragAndDrop::isInventoryDropAcceptable(obj, item)) + { + accept = false; + break; + } + } + return accept; +} + +void FSPanelFace::onCommitPbr() +{ + if (!mMaterialCtrlPBR->getTentative()) + { + // we grab the item id first, because we want to do a + // permissions check in the selection manager. ARGH! + LLUUID id = mMaterialCtrlPBR->getImageItemID(); + if (id.isNull()) + { + id = mMaterialCtrlPBR->getImageAssetID(); + } + if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id)) + { + // If failed to set material, refresh mMaterialCtrlPBR's value + refresh(); + } + } +} + +void FSPanelFace::onCancelPbr() +{ + LLSelectMgr::getInstance()->selectionRevertGLTFMaterials(); +} + +void FSPanelFace::onSelectPbr() +{ + LLSelectMgr::getInstance()->saveSelectedObjectTextures(); + onCommitPbr(); +} + +void FSPanelFace::onCommitPbr(const LLUICtrl* pbr_ctrl) +{ + LL_WARNS("FACEPANELM") << "committed pbr map " << pbr_ctrl->getName() << LL_ENDL; + + if (pbr_ctrl == mBaseTexturePBR) + { + mUnsavedChanges |= MATERIAL_BASE_COLOR_TEX_DIRTY; + } + else if (pbr_ctrl == mNormalTexturePBR) + { + mUnsavedChanges |= MATERIAL_NORMAL_TEX_DIRTY; + } + else if (pbr_ctrl == mEmissiveTexturePBR) + { + mUnsavedChanges |= MATERIAL_EMISIVE_TEX_DIRTY; + } + else if (pbr_ctrl == mORMTexturePBR) + { + mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY; + } + else if (pbr_ctrl == mBaseTintPBR) + { + mUnsavedChanges |= MATERIAL_BASE_COLOR_DIRTY; + } + else if (pbr_ctrl == mEmissiveTintPBR) + { + mUnsavedChanges |= MATERIAL_EMISIVE_COLOR_DIRTY; + } + else if (pbr_ctrl == mCheckDoubleSidedPBR) + { + mUnsavedChanges |= MATERIAL_DOUBLE_SIDED_DIRTY; + } + else if (pbr_ctrl == mAlphaPBR) + { + mUnsavedChanges |= MATERIAL_BASE_COLOR_DIRTY; + } + else if (pbr_ctrl == mAlphaModePBR) + { + mUnsavedChanges |= MATERIAL_ALPHA_MODE_DIRTY; + } + else if (pbr_ctrl == mMaskCutoffPBR) + { + mUnsavedChanges |= MATERIAL_ALPHA_CUTOFF_DIRTY; + } + else if (pbr_ctrl == mMetallicFactorPBR) + { + mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY; + } + else if (pbr_ctrl == mRoughnessFactorPBR) + { + mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY; + } +} + +// highlights PBR material parameters that are part of a material override +void FSPanelFace::updatePBROverrideDisplay() +{ + LLColor4 labelTextColor = LLUIColorTable::instance().getColor("LabelTextColor"); + LLColor4 emphasisColor = LLUIColorTable::instance().getColor("EmphasisColor"); // TODO: maybe create distinct color for skins -Zi + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + + if (!objectp || !node) + { + return; + } + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), objectp->getNumFaces()); + for (S32 te = 0; te < num_tes; ++te) + { + if (!node->isTESelected(te)) + { + continue; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (!tep) + { + continue; + } + + LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride(); + if (!override_material) + { + continue; + } + + LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") + << override_material << "\n" + << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] << "\n" + << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] << "\n" + << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] << "\n" + << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] << "\n" + << override_material->mBaseColor << "\n" + << override_material->mEmissiveColor << "\n" + << override_material->mAlphaMode << "\n" + << override_material->mAlphaCutoff << "\n" + << override_material->mMetallicFactor << "\n" + << override_material->mRoughnessFactor << "\n" + << override_material->mDoubleSided << "\n" + << LL_ENDL; + + mBaseTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].isNull() ? labelTextColor : emphasisColor); + mNormalTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].isNull() ? labelTextColor : emphasisColor); + mORMTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].isNull() ? labelTextColor : emphasisColor); + mEmissiveTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].isNull() ? labelTextColor : emphasisColor); + + mBaseTintPBR->setLabelColor(override_material->mBaseColor == LLGLTFMaterial::getDefaultBaseColor() ? labelTextColor : emphasisColor); + mAlphaPBR->setLabelColor(override_material->mBaseColor == LLGLTFMaterial::getDefaultBaseColor() ? labelTextColor : emphasisColor); + mLabelAlphaModePBR->setColor(override_material->mAlphaMode == LLGLTFMaterial::getDefaultAlphaMode() ? labelTextColor : emphasisColor); + mMaskCutoffPBR->setLabelColor(override_material->mAlphaCutoff == LLGLTFMaterial::getDefaultAlphaCutoff() ? labelTextColor : emphasisColor); + + mMetallicFactorPBR->setLabelColor(override_material->mMetallicFactor == LLGLTFMaterial::getDefaultMetallicFactor() ? labelTextColor : emphasisColor); + mRoughnessFactorPBR->setLabelColor(override_material->mRoughnessFactor == LLGLTFMaterial::getDefaultRoughnessFactor() ? labelTextColor : emphasisColor); + + mEmissiveTintPBR->setLabelColor(override_material->mEmissiveColor == LLGLTFMaterial::getDefaultEmissiveColor() ? labelTextColor : emphasisColor); + + mCheckDoubleSidedPBR->setEnabledColor(override_material->mDoubleSided == LLGLTFMaterial::getDefaultDoubleSided() ? labelTextColor : emphasisColor); + // refresh checkbox, as LLCheckBoxCtrl does not refresh its label when you change the color + mCheckDoubleSidedPBR->setEnabled(mCheckDoubleSidedPBR->getEnabled()); + + break; + } +} + +void FSPanelFace::onCancelPbr(const LLUICtrl* map_ctrl) +{ + // TODO -Zi +} + +void FSPanelFace::onSelectPbr(const LLUICtrl* map_ctrl) +{ + onCommitPbr(map_ctrl); +} + +BOOL FSPanelFace::onDragTexture(LLInventoryItem* item) +{ + bool accept = true; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* obj = node->getObject(); + if (!LLToolDragAndDrop::isInventoryDropAcceptable(obj, item)) + { + accept = false; + break; + } + } + return accept; +} + +void FSPanelFace::onCommitTexture(const LLUICtrl* ctrl, const LLSD& data) +{ + LL_WARNS() << "onCommitTexture" << LL_ENDL; + add(LLStatViewer::EDIT_TEXTURE, 1); + + LLSelectMgr::getInstance()->saveSelectedObjectTextures(); + sendTexture(); + + LLGLenum image_format; + bool identical_image_format = false; + LLSelectedTE::getImageFormat(image_format, identical_image_format); + + U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + switch (image_format) + { + case GL_RGBA: + case GL_ALPHA: + { + alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; + } + break; + + case GL_RGB: break; + default: + { + LL_WARNS() << "Unexpected tex format in FSPanelFace...resorting to no alpha" << LL_ENDL; + } + break; + } + + mComboAlphaMode->selectNthItem(alpha_mode); + + LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode()); + + // can't just pass "ctrl" on because it's const, and we also need to check + // the ctrl type so we make sure it's a texture swatch + onTextureSelectionChanged(ctrl->getName()); +} + +void FSPanelFace::onCommitNormalTexture(const LLUICtrl* ctrl, const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + LLUUID nmap_id = getCurrentNormalMap(); + sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE); + onTextureSelectionChanged(ctrl->getName()); +} + +void FSPanelFace::onCommitSpecularTexture(const LLUICtrl* ctrl, const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + sendShiny(SHINY_TEXTURE); + onTextureSelectionChanged(ctrl->getName()); +} + +void FSPanelFace::onCloseTexturePicker(const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + updateUI(); +} + +void FSPanelFace::onCancelTexture() +{ + LL_WARNS() << "onCancelTexture" << LL_ENDL; + LLSelectMgr::getInstance()->selectionRevertTextures(); +} + +void FSPanelFace::onCancelNormalTexture() +{ + U8 bumpy = 0; + bool identical_bumpy = false; + LLSelectedTE::getBumpmap(bumpy, identical_bumpy); + LLUUID normal_map_id = mBumpyTextureCtrl->getImageAssetID(); + bumpy = normal_map_id.isNull() ? bumpy : BUMPY_TEXTURE; + sendBump(bumpy); +} + +void FSPanelFace::onCancelSpecularTexture() +{ + U8 shiny = 0; + bool identical_shiny = false; + LLSelectedTE::getShiny(shiny, identical_shiny); + LLUUID spec_map_id = mShinyTextureCtrl->getImageAssetID(); + shiny = spec_map_id.isNull() ? shiny : SHINY_TEXTURE; + sendShiny(shiny); +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to edit existing media settings on a prim or prim face +// TODO: test if there is media on the item and only allow editing if present +// NOTE: there is no actual "Button" Edit Media, but this function is called from +// onClickBtnAddMedia() where needed, so the naming is probably just old cruft -Zi +void FSPanelFace::onClickBtnEditMedia() +{ + refreshMedia(); + LLFloaterReg::showInstance("media_settings"); +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to delete media from a prim or prim face +void FSPanelFace::onClickBtnDeleteMedia() +{ + LLNotificationsUtil::add("DeleteMedia", LLSD(), LLSD(), boost::bind(&FSPanelFace::deleteMediaConfirm, this, _1, _2)); +} + +////////////////////////////////////////////////////////////////////////////// +// called when a user wants to add media to a prim or prim face +void FSPanelFace::onClickBtnAddMedia() +{ + // check if multiple faces are selected + if (LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected()) + { + refreshMedia(); + LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), boost::bind(&FSPanelFace::multipleFacesSelectedConfirm, this, _1, _2)); + } + else + { + onClickBtnEditMedia(); + } +} + +bool FSPanelFace::deleteMediaConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch (option) + { + case 0: // "Yes" + LLSelectMgr::getInstance()->selectionSetMedia(0, LLSD()); + if (LLFloaterReg::instanceVisible("media_settings")) + { + LLFloaterReg::hideInstance("media_settings"); + } + break; + + case 1: // "No" + default: + break; + } + return false; +} + +bool FSPanelFace::multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch (option) + { + case 0: // "Yes" + LLFloaterReg::showInstance("media_settings"); + break; + + case 1: // "No" + default: + break; + } + return false; +} + +//static +void FSPanelFace::syncOffsetX(FSPanelFace* self, F32 offsetU) +{ + LLSelectedTEMaterial::setNormalOffsetX(self,offsetU); + LLSelectedTEMaterial::setSpecularOffsetX(self,offsetU); + self->mCtrlTexOffsetU->forceSetValue(offsetU); + self->sendTextureInfo(); +} + +//static +void FSPanelFace::syncOffsetY(FSPanelFace* self, F32 offsetV) +{ + LLSelectedTEMaterial::setNormalOffsetY(self,offsetV); + LLSelectedTEMaterial::setSpecularOffsetY(self,offsetV); + self->mCtrlTexOffsetV->forceSetValue(offsetV); + self->sendTextureInfo(); +} + +void FSPanelFace::onCommitMaterialBumpyOffsetX() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetX(this, getCurrentBumpyOffsetU()); + } + else + { + LLSelectedTEMaterial::setNormalOffsetX(this, getCurrentBumpyOffsetU()); + } +} + +void FSPanelFace::onCommitMaterialBumpyOffsetY() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetY(this, getCurrentBumpyOffsetV()); + } + else + { + LLSelectedTEMaterial::setNormalOffsetY(this, getCurrentBumpyOffsetV()); + } +} + +void FSPanelFace::onCommitMaterialShinyOffsetX() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetX(this, getCurrentShinyOffsetU()); + } + else + { + LLSelectedTEMaterial::setSpecularOffsetX(this, getCurrentShinyOffsetU()); + } +} + +void FSPanelFace::onCommitMaterialShinyOffsetY() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetY(this, getCurrentShinyOffsetV()); + } + else + { + LLSelectedTEMaterial::setSpecularOffsetY(this, getCurrentShinyOffsetV()); + } +} + +//static +void FSPanelFace::syncRepeatX(FSPanelFace* self, F32 scaleU) +{ + LLSelectedTEMaterial::setNormalRepeatX(self,scaleU); + LLSelectedTEMaterial::setSpecularRepeatX(self,scaleU); + self->sendTextureInfo(); +} + +//static +void FSPanelFace::syncRepeatY(FSPanelFace* self, F32 scaleV) +{ + LLSelectedTEMaterial::setNormalRepeatY(self,scaleV); + LLSelectedTEMaterial::setSpecularRepeatY(self,scaleV); + self->sendTextureInfo(); +} + +void FSPanelFace::onCommitMaterialBumpyScaleX() +{ + F32 bumpy_scale_u = getCurrentBumpyScaleU(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_u *= 0.5f; + } + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexScaleU->forceSetValue(getCurrentBumpyScaleU()); + syncRepeatX(this, bumpy_scale_u); + } + else + { + LLSelectedTEMaterial::setNormalRepeatX(this, bumpy_scale_u); + } +} + +void FSPanelFace::onCommitMaterialBumpyScaleY() +{ + F32 bumpy_scale_v = getCurrentBumpyScaleV(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_v *= 0.5f; + } + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexScaleV->forceSetValue(getCurrentBumpyScaleV()); + syncRepeatY(this, bumpy_scale_v); + } + else + { + LLSelectedTEMaterial::setNormalRepeatY(this, bumpy_scale_v); + } +} + +void FSPanelFace::onCommitMaterialShinyScaleX() +{ + F32 shiny_scale_u = getCurrentShinyScaleU(); + if (isIdenticalPlanarTexgen()) + { + shiny_scale_u *= 0.5f; + } + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexScaleU->forceSetValue(getCurrentShinyScaleU()); + syncRepeatX(this, shiny_scale_u); + } + else + { + LLSelectedTEMaterial::setSpecularRepeatX(this, shiny_scale_u); + } +} + +void FSPanelFace::onCommitMaterialShinyScaleY() +{ + F32 shiny_scale_v = getCurrentShinyScaleV(); + if (isIdenticalPlanarTexgen()) + { + shiny_scale_v *= 0.5f; + } + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexScaleV->forceSetValue(getCurrentShinyScaleV()); + syncRepeatY(this, shiny_scale_v); + } + else + { + LLSelectedTEMaterial::setSpecularRepeatY(this, shiny_scale_v); + } +} + +//static +void FSPanelFace::syncMaterialRot(FSPanelFace* self, F32 rot, int te) +{ + LLSelectedTEMaterial::setNormalRotation(self,rot * DEG_TO_RAD, te); + LLSelectedTEMaterial::setSpecularRotation(self,rot * DEG_TO_RAD, te); + self->sendTextureInfo(); +} + +void FSPanelFace::onCommitMaterialBumpyRot() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexRot->forceSetValue(getCurrentBumpyRot()); + syncMaterialRot(this, getCurrentBumpyRot()); + } + else + { + if (mCheckPlanarAlign->getValue().asBoolean()) + { + LLFace* last_face = NULL; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); + FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + } + else + { + LLSelectedTEMaterial::setNormalRotation(this, getCurrentBumpyRot() * DEG_TO_RAD); + } + } +} + +void FSPanelFace::onCommitMaterialShinyRot() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + mCtrlTexRot->forceSetValue(getCurrentShinyRot()); + syncMaterialRot(this, getCurrentShinyRot()); + } + else + { + if (mCheckPlanarAlign->getValue().asBoolean()) + { + LLFace* last_face = NULL; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); + FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + } + else + { + LLSelectedTEMaterial::setSpecularRotation(this, getCurrentShinyRot() * DEG_TO_RAD); + } + } +} + +void FSPanelFace::onCommitMaterialGloss() +{ + LLSelectedTEMaterial::setSpecularLightExponent(this, getCurrentGlossiness()); +} + +void FSPanelFace::onCommitMaterialEnv() +{ + LLSelectedTEMaterial::setEnvironmentIntensity(this, getCurrentEnvIntensity()); +} + +void FSPanelFace::onCommitMaterialMaskCutoff() +{ + LLSelectedTEMaterial::setAlphaMaskCutoff(this, getCurrentAlphaMaskCutoff()); +} + +void FSPanelFace::onCommitTextureScaleX() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + F32 bumpy_scale_u = mCtrlTexScaleU->getValue().asReal(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_u *= 0.5f; + } + syncRepeatX(this, bumpy_scale_u); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + +void FSPanelFace::onCommitTextureScaleY() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + F32 bumpy_scale_v = mCtrlTexScaleV->getValue().asReal(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_v *= 0.5f; + } + syncRepeatY(this, bumpy_scale_v); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + +void FSPanelFace::onCommitTextureRot() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncMaterialRot(this, mCtrlTexRot->getValue().asReal()); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + + +void FSPanelFace::onCommitTextureOffsetX() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetX(this, mCtrlTexOffsetU->getValue().asReal()); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + +void FSPanelFace::onCommitTextureOffsetY() +{ + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + syncOffsetY(this, mCtrlTexOffsetV->getValue().asReal()); + } + else + { + sendTextureInfo(); + } + updateUI(true); +} + +// Commit the number of repeats per meter +void FSPanelFace::onCommitRepeatsPerMeter() +{ + S32 materials_media = getCurrentMaterialType(); + S32 material_type = 0; + // TODO: check if repeats per meter is even used for PBR -Zi + if (materials_media == MATMEDIA_PBR) + { + material_type = getCurrentPBRChannel(); + } + + if (materials_media == MATMEDIA_MATERIAL) + { + material_type = getCurrentMatChannel(); + } + + F32 repeats_per_meter = mCtrlRpt->getValue().asReal(); + + F32 obj_scale_s = 1.0f; + F32 obj_scale_t = 1.0f; + + bool identical_scale_s = false; + bool identical_scale_t = false; + + LLSelectedTE::getObjectScaleS(obj_scale_s, identical_scale_s); + LLSelectedTE::getObjectScaleS(obj_scale_t, identical_scale_t); + + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter); + + mCtrlBumpyScaleU->setValue(obj_scale_s * repeats_per_meter); + mCtrlBumpyScaleV->setValue(obj_scale_t * repeats_per_meter); + + LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter); + LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter); + + mCtrlShinyScaleU->setValue(obj_scale_s * repeats_per_meter); + mCtrlShinyScaleV->setValue(obj_scale_t * repeats_per_meter); + + LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter); + LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter); + } + else + { + switch (material_type) + { + case MATTYPE_DIFFUSE: + { + LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter); + } + break; + + case MATTYPE_NORMAL: + { + mCtrlBumpyScaleU->setValue(obj_scale_s * repeats_per_meter); + mCtrlBumpyScaleV->setValue(obj_scale_t * repeats_per_meter); + + LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter); + LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter); + } + break; + + case MATTYPE_SPECULAR: + { + mCtrlShinyScaleU->setValue(obj_scale_s * repeats_per_meter); + mCtrlShinyScaleV->setValue(obj_scale_t * repeats_per_meter); + + LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter); + LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter); + } + break; + + default: + llassert(false); + break; + } + } + + // vertical scale and repeats per meter depends on each other, so force set on changes + updateUI(true); +} + +struct FSPanelFaceSetMediaFunctor : public LLSelectedTEFunctor +{ + virtual bool apply(LLViewerObject* object, S32 te) + { + viewer_media_t pMediaImpl; + + const LLTextureEntry &tep = object->getTEref(te); + const LLMediaEntry* mep = tep.hasMedia() ? tep.getMediaData() : NULL; + if (mep) + { + pMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID()); + } + + if (pMediaImpl.isNull()) + { + // If we didn't find face media for this face, check whether this face is showing parcel media. + pMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep.getID()); + } + + if (pMediaImpl.notNull()) + { + LLPluginClassMedia *media = pMediaImpl->getMediaPlugin(); + if(media) + { + S32 media_width = media->getWidth(); + S32 media_height = media->getHeight(); + S32 texture_width = media->getTextureWidth(); + S32 texture_height = media->getTextureHeight(); + F32 scale_s = (F32)media_width / (F32)texture_width; + F32 scale_t = (F32)media_height / (F32)texture_height; + + // set scale and adjust offset + object->setTEScaleS( te, scale_s ); + object->setTEScaleT( te, scale_t ); // don't need to flip Y anymore since QT does this for us now. + object->setTEOffsetS( te, -( 1.0f - scale_s ) / 2.0f ); + object->setTEOffsetT( te, -( 1.0f - scale_t ) / 2.0f ); + } + } + return true; + }; +}; + +void FSPanelFace::onClickAutoFix() +{ + FSPanelFaceSetMediaFunctor setfunc; + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); + + FSPanelFaceSendFunctor sendfunc; + LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc); +} + +void FSPanelFace::onAlignTexture() +{ + alignTextureLayer(); +} + +void FSPanelFace::onClickBtnSavePBR() +{ + LLMaterialEditor::saveObjectsMaterialAs(); +} + +enum EPasteMode +{ + PASTE_COLOR, + PASTE_TEXTURE +}; + +struct FSPanelFacePasteTexFunctor : public LLSelectedTEFunctor +{ + public: + FSPanelFacePasteTexFunctor(FSPanelFace* panel, EPasteMode mode) : + mPanelFace(panel), + mMode(mode) + { + } + + virtual bool apply(LLViewerObject* objectp, S32 te) + { + switch(mMode) + { + case PASTE_COLOR: + mPanelFace->onPasteColor(objectp, te); + break; + + case PASTE_TEXTURE: + mPanelFace->onPasteTexture(objectp, te); + break; + } + return true; + } + + private: + FSPanelFace *mPanelFace; + EPasteMode mMode; +}; + +struct FSPanelFaceUpdateFunctor : public LLSelectedObjectFunctor +{ + public: + FSPanelFaceUpdateFunctor(bool update_media) : + mUpdateMedia(update_media) + { + } + + virtual bool apply(LLViewerObject* object) + { + object->sendTEUpdate(); + + if (mUpdateMedia) + { + LLVOVolume *vo = dynamic_cast(object); + if (vo && vo->hasMedia()) + { + vo->sendMediaDataUpdate(); + } + } + return true; + } + + private: + bool mUpdateMedia; +}; + +struct FSPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor +{ + virtual bool apply(LLViewerObject* objectp, S32 te) + { + if (objectp && objectp->getTE(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + const LLMediaEntry *media_data = tep->getMediaData(); + if (media_data) + { + if (media_data->getCurrentURL().empty() && media_data->getAutoPlay()) + { + viewer_media_t media_impl = + LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID()); + if (media_impl) + { + media_impl->navigateHome(); + } + } + } + } + return true; + } +}; + +void FSPanelFace::onCopyColor() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + return; + } + + if (mClipboardParams.has("color")) + { + mClipboardParams["color"].clear(); + } + else + { + mClipboardParams["color"] = LLSD::emptyArray(); + } + + std::map asset_item_map; + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + mClipboardParams["color_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + LLSD te_data; + + // asLLSD() includes media + te_data["te"] = tep->asLLSD(); // Note: includes a lot more than just color/alpha/glow + + mClipboardParams["color"].append(te_data); + } + } + } +} + +void FSPanelFace::onPasteColor() +{ + if (!mClipboardParams.has("color")) + { + return; + } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + // not supposed to happen + LL_WARNS() << "Failed to paste color due to missing or wrong selection" << LL_ENDL; + return; + } + + bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + LLSD &clipboard = mClipboardParams["color"]; // array + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + S32 compare_tes = num_tes; + + if (face_selection_mode) + { + compare_tes = 0; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + compare_tes++; + } + } + } + + // we can copy if single face was copied in edit face mode or if face count matches + if (!((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) + && compare_tes != clipboard.size()) + { + LLSD notif_args; + if (face_selection_mode) + { + static std::string reason = getString("paste_error_face_selection_mismatch"); + notif_args["REASON"] = reason; + } + else + { + static std::string reason = getString("paste_error_object_face_count_mismatch"); + notif_args["REASON"] = reason; + } + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + FSPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR); + selected_objects->applyToTEs(&paste_func); + + FSPanelFaceUpdateFunctor sendfunc(false); + selected_objects->applyToObjects(&sendfunc); +} + +void FSPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) +{ + LLSD te_data; + LLSD &clipboard = mClipboardParams["color"]; // array + if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) + { + te_data = *(clipboard.beginArray()); + } + else if (clipboard[te]) + { + te_data = clipboard[te]; + } + else + { + return; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + if (te_data.has("te")) + { + // Color / Alpha + if (te_data["te"].has("colors")) + { + LLColor4 color = tep->getColor(); + + LLColor4 clip_color; + clip_color.setValue(te_data["te"]["colors"]); + + // Color + color.mV[VRED] = clip_color.mV[VRED]; + color.mV[VGREEN] = clip_color.mV[VGREEN]; + color.mV[VBLUE] = clip_color.mV[VBLUE]; + + // Alpha + color.mV[VALPHA] = clip_color.mV[VALPHA]; + + objectp->setTEColor(te, color); + } + + // Color/fullbright + if (te_data["te"].has("fullbright")) + { + objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger()); + } + + // Glow + if (te_data["te"].has("glow")) + { + objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal()); + } + } + } +} + +void FSPanelFace::onCopyTexture() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1 + || !LLMaterialEditor::canClipboardObjectsMaterial()) + { + return; + } + + if (mClipboardParams.has("texture")) + { + mClipboardParams["texture"].clear(); + } + else + { + mClipboardParams["texture"] = LLSD::emptyArray(); + } + + std::map asset_item_map; + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), objectp->getNumFaces()); + mClipboardParams["texture_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + LLSD te_data; + + // asLLSD() includes media + te_data["te"] = tep->asLLSD(); + te_data["te"]["shiny"] = tep->getShiny(); + te_data["te"]["bumpmap"] = tep->getBumpmap(); + te_data["te"]["bumpshiny"] = tep->getBumpShiny(); + te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright(); + te_data["te"]["texgen"] = tep->getTexGen(); + te_data["te"]["pbr"] = objectp->getRenderMaterialID(te); + if (tep->getGLTFMaterialOverride() != nullptr) + { + te_data["te"]["pbr_override"] = tep->getGLTFMaterialOverride()->asJSON(); + } + + if (te_data["te"].has("imageid")) + { + LLUUID item_id; + LLUUID id = te_data["te"]["imageid"].asUUID(); + bool from_library = get_is_predefined_texture(id); + bool full_perm = from_library; + + if (!full_perm + && objectp->permCopy() + && objectp->permTransfer() + && objectp->permModify()) + { + // If agent created this object and nothing is limiting permissions, mark as full perm + // If agent was granted permission to edit objects owned and created by somebody else, mark full perm + // This check is not perfect since we can't figure out whom textures belong to so this ended up restrictive + std::string creator_app_link; + LLUUID creator_id; + LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link); + full_perm = objectp->mOwnerID == creator_id; + } + + if (id.notNull() && !full_perm) + { + std::map::iterator iter = asset_item_map.find(id); + if (iter != asset_item_map.end()) + { + item_id = iter->second; + } + else + { + // What this does is simply searches inventory for item with same asset id, + // as result it is highly unreliable, leaves little control to user, borderline hack + // but there are little options to preserve permissions - multiple inventory + // items might reference same asset and inventory search is expensive. + bool no_transfer = false; + if (objectp->getInventoryItemByAsset(id)) + { + no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm(); + } + item_id = get_copy_free_item_by_asset_id(id, no_transfer); + // record value to avoid repeating inventory search when possible + asset_item_map[id] = item_id; + } + } + + if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID())) + { + full_perm = true; + from_library = true; + } + + // TODO: why scope this? -Zi + { + te_data["te"]["itemfullperm"] = full_perm; + te_data["te"]["fromlibrary"] = from_library; + + // If full permission object, texture is free to copy, + // but otherwise we need to check inventory and extract permissions + // + // Normally we care only about restrictions for current user and objects + // don't inherit any 'next owner' permissions from texture, so there is + // no need to record item id if full_perm==true + if (!full_perm && !from_library && item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp) + { + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + te_data["te"]["imageitemid"] = item_id; + te_data["te"]["itemfullperm"] = itemp->getIsFullPerm(); + if (!itemp->isFinished()) + { + // needed for dropTextureAllFaces + LLInventoryModelBackgroundFetch::instance().start(item_id, false); + } + } + } + } + } + } + + LLMaterialPtr material_ptr = tep->getMaterialParams(); + if (!material_ptr.isNull()) + { + LLSD mat_data; + + mat_data["NormMap"] = material_ptr->getNormalID(); + mat_data["SpecMap"] = material_ptr->getSpecularID(); + + mat_data["NormRepX"] = material_ptr->getNormalRepeatX(); + mat_data["NormRepY"] = material_ptr->getNormalRepeatY(); + mat_data["NormOffX"] = material_ptr->getNormalOffsetX(); + mat_data["NormOffY"] = material_ptr->getNormalOffsetY(); + mat_data["NormRot"] = material_ptr->getNormalRotation(); + + mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX(); + mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY(); + mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX(); + mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY(); + mat_data["SpecRot"] = material_ptr->getSpecularRotation(); + + mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue(); + mat_data["SpecExp"] = material_ptr->getSpecularLightExponent(); + mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity(); + mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff(); + mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode(); + + // Replace no-copy textures, destination texture will get used instead if available + if (mat_data.has("NormMap")) + { + LLUUID id = mat_data["NormMap"].asUUID(); + if (id.notNull() && !get_can_copy_texture(id)) + { + mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["NormMapNoCopy"] = true; + } + } + if (mat_data.has("SpecMap")) + { + LLUUID id = mat_data["SpecMap"].asUUID(); + if (id.notNull() && !get_can_copy_texture(id)) + { + mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["SpecMapNoCopy"] = true; + } + } + + te_data["material"] = mat_data; + } + + mClipboardParams["texture"].append(te_data); + } + } + } +} + +void FSPanelFace::onPasteTexture() +{ + if (!mClipboardParams.has("texture")) + { + return; + } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1 + || !LLMaterialEditor::canClipboardObjectsMaterial()) + { + // not supposed to happen + LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL; + return; + } + + bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + LLSD &clipboard = mClipboardParams["texture"]; // array + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + S32 compare_tes = num_tes; + + if (face_selection_mode) + { + compare_tes = 0; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + compare_tes++; + } + } + } + + // we can copy if single face was copied in edit face mode or if face count matches + if (!((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) + && compare_tes != clipboard.size()) + { + LLSD notif_args; + if (face_selection_mode) + { + static std::string reason = getString("paste_error_face_selection_mismatch"); + notif_args["REASON"] = reason; + } + else + { + static std::string reason = getString("paste_error_object_face_count_mismatch"); + notif_args["REASON"] = reason; + } + + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + + bool full_perm_object = true; + + LLSD::array_const_iterator iter = clipboard.beginArray(); + LLSD::array_const_iterator end = clipboard.endArray(); + + for (; iter != end; ++iter) + { + const LLSD& te_data = *iter; + if (te_data.has("te") && te_data["te"].has("imageid")) + { + bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + full_perm_object &= full_perm; + if (!full_perm) + { + if (te_data["te"].has("imageitemid")) + { + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (!itemp) + { + // image might be in object's inventory, but it can be not up to date + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + } + } + else + { + // Item was not found on 'copy' stage + // Since this happened at copy, might be better to either show this + // at copy stage or to drop clipboard here + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + } + } + } + + if (!full_perm_object) + { + LLNotificationsUtil::add("FacePasteTexturePermissions"); + } + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + FSPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); + selected_objects->applyToTEs(&paste_func); + + FSPanelFaceUpdateFunctor sendfunc(true); + selected_objects->applyToObjects(&sendfunc); + + LLGLTFMaterialList::flushUpdates(); + + FSPanelFaceNavigateHomeFunctor navigate_home_func; + selected_objects->applyToTEs(&navigate_home_func); +} + +void FSPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) +{ + LLSD te_data; + LLSD &clipboard = mClipboardParams["texture"]; // array + if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) + { + te_data = *(clipboard.beginArray()); + } + else if (clipboard[te]) + { + te_data = clipboard[te]; + } + else + { + return; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + if (te_data.has("te")) + { + // Texture + bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean(); + if (te_data["te"].has("imageid")) + { + const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id + LLViewerInventoryItem* itemp_res = NULL; + + if (te_data["te"].has("imageitemid")) + { + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + itemp_res = itemp; + } + else + { + // Theoretically shouldn't happen, but if it does happen, we + // might need to add a notification to user that paste will fail + // since inventory isn't fully loaded + LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL; + } + } + } + // for case when item got removed from inventory after we pressed 'copy' + // or texture got pasted into previous object + if (!itemp_res && !full_perm) + { + // Due to checks for imageitemid in FSPanelFace::onPasteTexture() this should no longer be reachable. + LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL; + // Todo: fix this, we are often searching same texture multiple times (equal to number of faces) + // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(imageid); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + // Extremely unreliable and performance unfriendly. + // But we need this to check permissions and it is how texture control finds items + for (S32 i = 0; i < items.size(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + itemp_res = itemp; + break; // first match + } + } + } + } + + if (itemp_res) + { + if (te == -1) // all faces + { + LLToolDragAndDrop::dropTextureAllFaces(objectp, + itemp_res, + from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null, + false); + } + else // one face + { + LLToolDragAndDrop::dropTextureOneFace(objectp, + te, + itemp_res, + from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null, + false, + 0); + } + } + // not an inventory item or no complete items + else if (full_perm) + { + // Either library, local or existed as fullperm when user made a copy + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + objectp->setTEImage(U8(te), image); + } + } + + if (te_data["te"].has("bumpmap")) + { + objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger()); + } + if (te_data["te"].has("bumpshiny")) + { + objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger()); + } + if (te_data["te"].has("bumpfullbright")) + { + objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger()); + } + if (te_data["te"].has("texgen")) + { + objectp->setTETexGen(te, (U8)te_data["te"]["texgen"].asInteger()); + } + + // PBR/GLTF + if (te_data["te"].has("pbr")) + { + objectp->setRenderMaterialID(te, te_data["te"]["pbr"].asUUID(), false /*managing our own update*/); + tep->setGLTFRenderMaterial(nullptr); + tep->setGLTFMaterialOverride(nullptr); + + LLSD override_data; + override_data["object_id"] = objectp->getID(); + override_data["side"] = te; + if (te_data["te"].has("pbr_override")) + { + override_data["gltf_json"] = te_data["te"]["pbr_override"]; + } + else + { + override_data["gltf_json"] = ""; + } + + override_data["asset_id"] = te_data["te"]["pbr"].asUUID(); + + LLGLTFMaterialList::queueUpdate(override_data); + } + else + { + objectp->setRenderMaterialID(te, LLUUID::null, false /*send in bulk later*/ ); + tep->setGLTFRenderMaterial(nullptr); + tep->setGLTFMaterialOverride(nullptr); + + // blank out most override data on the server + LLGLTFMaterialList::queueApply(objectp, te, LLUUID::null); + } + + // Texture map + if (te_data["te"].has("scales") && te_data["te"].has("scalet")) + { + objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal()); + } + if (te_data["te"].has("offsets") && te_data["te"].has("offsett")) + { + objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal()); + } + if (te_data["te"].has("imagerot")) + { + objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal()); + } + + // Media + if (te_data["te"].has("media_flags")) + { + U8 media_flags = te_data["te"]["media_flags"].asInteger(); + objectp->setTEMediaFlags(te, media_flags); + LLVOVolume *vo = dynamic_cast(objectp); + if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY)) + { + vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/); + } + } + else + { + // Keep media flags on destination unchanged + } + } + + if (te_data.has("material")) + { + LLUUID object_id = objectp->getID(); + + // Normal + // Replace placeholders with target's + if (te_data["material"].has("NormMapNoCopy")) + { + LLMaterialPtr material = tep->getMaterialParams(); + if (material.notNull()) + { + LLUUID id = material->getNormalID(); + if (id.notNull()) + { + te_data["material"]["NormMap"] = id; + } + } + } + + LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id); + LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id); + + // Specular + // Replace placeholders with target's + if (te_data["material"].has("SpecMapNoCopy")) + { + LLMaterialPtr material = tep->getMaterialParams(); + if (material.notNull()) + { + LLUUID id = material->getSpecularID(); + if (id.notNull()) + { + te_data["material"]["SpecMap"] = id; + } + } + } + + LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id); + LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id); + LLColor4U spec_color(te_data["material"]["SpecColor"]); + LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te); + LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); + LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); + LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["DiffuseAlphaMode"].asInteger(), te, object_id); + LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["AlphaMaskCutoff"].asInteger(), te, object_id); + + if (te_data.has("te") && te_data["te"].has("shiny")) + { + objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger()); + } + } + } +} + +void FSPanelFace::onCopyFaces() +{ + onCopyTexture(); + onCopyColor(); + mBtnPasteFaces->setEnabled(!mClipboardParams.emptyMap() && (mClipboardParams.has("color") || mClipboardParams.has("texture"))); +} + +void FSPanelFace::onPasteFaces() +{ + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + FSPanelFacePasteTexFunctor paste_texture_func(this, PASTE_TEXTURE); + selected_objects->applyToTEs(&paste_texture_func); + + FSPanelFacePasteTexFunctor paste_color_func(this, PASTE_COLOR); + selected_objects->applyToTEs(&paste_color_func); + + FSPanelFaceUpdateFunctor sendfunc(true); + selected_objects->applyToObjects(&sendfunc); + + FSPanelFaceNavigateHomeFunctor navigate_home_func; + selected_objects->applyToTEs(&navigate_home_func); +} + +void FSPanelFace::onCommitPlanarAlign() +{ + getState(); + sendTextureInfo(); +} + +void FSPanelFace::updateGLTFTextureTransform(float value, U32 pbr_channel, std::function edit) +{ + U32 texture_info_start; + U32 texture_info_end; + + const LLGLTFMaterial::TextureInfo texture_info = mPBRChannelToTextureInfo[pbr_channel]; + if (texture_info == LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT) + { + texture_info_start = 0; + texture_info_end = LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; + } + else + { + texture_info_start = mPBRChannelToTextureInfo[pbr_channel]; + texture_info_end = texture_info_start + 1; + } + + updateSelectedGLTFMaterials([&](LLGLTFMaterial* new_override) + { + for (U32 ti = texture_info_start; ti < texture_info_end; ++ti) + { + LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[(LLGLTFMaterial::TextureInfo)ti]; + edit(&new_transform); + } + }); +} + +void FSPanelFace::setMaterialOverridesFromSelection() +{ + // TODO: move to .h -Zi + std::map spinner_suffixes = + { + { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR, "_Base" }, + { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_NORMAL, "_Normal" }, + { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, "_Metallic" }, + { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_EMISSIVE, "_Emissive" } + }; + + bool read_transform = true; + LLGLTFMaterial::TextureTransform transform; + bool scale_u_same = true; + bool scale_v_same = true; + bool rotation_same = true; + bool offset_u_same = true; + bool offset_v_same = true; + + // Always iterate over the whole set of texture channels + for (U32 i = 0; i < LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT; ++i) + { + std::string spinner_suffix = spinner_suffixes[(LLGLTFMaterial::TextureInfo) i]; + + LLGLTFMaterial::TextureTransform this_transform; + + bool this_scale_u_same = true; + bool this_scale_v_same = true; + bool this_rotation_same = true; + bool this_offset_u_same = true; + bool this_offset_v_same = true; + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mScale[VX] : 0.f; + }, this_transform.mScale[VX], this_scale_u_same, true, 1e-3f); + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mScale[VY] : 0.f; + }, this_transform.mScale[VY], this_scale_v_same, true, 1e-3f); + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mRotation : 0.f; + }, this_transform.mRotation, this_rotation_same, true, 1e-3f); + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mOffset[VX] : 0.f; + }, this_transform.mOffset[VX], this_offset_u_same, true, 1e-3f); + + readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[i].mOffset[VY] : 0.f; + }, this_transform.mOffset[VY], this_offset_v_same, true, 1e-3f); + + scale_u_same = scale_u_same && this_scale_u_same; + scale_v_same = scale_v_same && this_scale_v_same; + rotation_same = rotation_same && this_rotation_same; + offset_u_same = offset_u_same && this_offset_u_same; + offset_v_same = offset_v_same && this_offset_v_same; + + if (read_transform) + { + read_transform = false; + transform = this_transform; + } + else + { + scale_u_same = scale_u_same && (this_transform.mScale[VX] == transform.mScale[VX]); + scale_v_same = scale_v_same && (this_transform.mScale[VY] == transform.mScale[VY]); + rotation_same = rotation_same && (this_transform.mRotation == transform.mRotation); + offset_u_same = offset_u_same && (this_transform.mOffset[VX] == transform.mOffset[VX]); + offset_v_same = offset_v_same && (this_transform.mOffset[VY] == transform.mOffset[VY]); + } + + LLUICtrl* gltfCtrlTextureScaleU = findChild("gltfTextureScaleU" + spinner_suffix); + LLUICtrl* gltfCtrlTextureScaleV = findChild("gltfTextureScaleV" + spinner_suffix); + LLUICtrl* gltfCtrlTextureRotation = findChild("gltfTextureRotation" + spinner_suffix); + LLUICtrl* gltfCtrlTextureOffsetU = findChild("gltfTextureOffsetU" + spinner_suffix); + LLUICtrl* gltfCtrlTextureOffsetV = findChild("gltfTextureOffsetV" + spinner_suffix); + + gltfCtrlTextureScaleU->setValue(this_transform.mScale[VX]); + gltfCtrlTextureScaleV->setValue(this_transform.mScale[VY]); + gltfCtrlTextureRotation->setValue(this_transform.mRotation * RAD_TO_DEG); + gltfCtrlTextureOffsetU->setValue(this_transform.mOffset[VX]); + gltfCtrlTextureOffsetV->setValue(this_transform.mOffset[VY]); + } + + LLUICtrl* gltfCtrlTextureScaleU = findChild("gltfTextureScaleU_All"); + LLUICtrl* gltfCtrlTextureScaleV = findChild("gltfTextureScaleV_All"); + LLUICtrl* gltfCtrlTextureRotation = findChild("gltfTextureRotation_All"); + LLUICtrl* gltfCtrlTextureOffsetU = findChild("gltfTextureOffsetU_All"); + LLUICtrl* gltfCtrlTextureOffsetV = findChild("gltfTextureOffsetV_All"); + + gltfCtrlTextureScaleU->setValue(transform.mScale[VX]); + gltfCtrlTextureScaleV->setValue(transform.mScale[VY]); + gltfCtrlTextureRotation->setValue(transform.mRotation * RAD_TO_DEG); + gltfCtrlTextureOffsetU->setValue(transform.mOffset[VX]); + gltfCtrlTextureOffsetV->setValue(transform.mOffset[VY]); + + gltfCtrlTextureScaleU->setTentative(!scale_u_same); + gltfCtrlTextureScaleV->setTentative(!scale_v_same); + gltfCtrlTextureRotation->setTentative(!rotation_same); + gltfCtrlTextureOffsetU->setTentative(!offset_u_same); + gltfCtrlTextureOffsetV->setTentative(!offset_v_same); +} + +void FSPanelFace::Selection::connect() +{ + if (!mSelectConnection.connected()) + { + mSelectConnection = LLSelectMgr::instance().mUpdateSignal.connect(boost::bind(&FSPanelFace::Selection::onSelectionChanged, this)); + } +} + +bool FSPanelFace::Selection::update() +{ + const bool changed = mChanged || compareSelection(); + mChanged = false; + return changed; +} + +void FSPanelFace::Selection::onSelectedObjectUpdated(const LLUUID& object_id, S32 side) +{ + if (object_id == mSelectedObjectID) + { + if (side == mLastSelectedSide) + { + mChanged = true; + } + else if (mLastSelectedSide == -1) // if last selected face was deselected + { + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + if (node && node->isTESelected(side)) + { + mChanged = true; + } + } + } +} + +bool FSPanelFace::Selection::compareSelection() +{ + if (!mNeedsSelectionCheck) + { + return false; + } + + mNeedsSelectionCheck = false; + + const S32 old_object_count = mSelectedObjectCount; + const S32 old_te_count = mSelectedTECount; + const LLUUID old_object_id = mSelectedObjectID; + const S32 old_side = mLastSelectedSide; + + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLSelectNode* node = selection->getFirstNode(); + if (node) + { + LLViewerObject* object = node->getObject(); + mSelectedObjectCount = selection->getObjectCount(); + mSelectedTECount = selection->getTECount(); + mSelectedObjectID = object->getID(); + mLastSelectedSide = node->getLastSelectedTE(); + } + else + { + mSelectedObjectCount = 0; + mSelectedTECount = 0; + mSelectedObjectID = LLUUID::null; + mLastSelectedSide = -1; + } + + const bool selection_changed = + old_object_count != mSelectedObjectCount + || old_te_count != mSelectedTECount + || old_object_id != mSelectedObjectID + || old_side != mLastSelectedSide; + + mChanged = mChanged || selection_changed; + + return selection_changed; +} + +void FSPanelFace::onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_data) +{ + // TODO: put into .h -Zi + std::map types = + { + { "all", PBRTYPE_RENDER_MATERIAL_ID }, + { "base", PBRTYPE_BASE_COLOR }, + { "normal", PBRTYPE_NORMAL }, + { "metallic", PBRTYPE_METALLIC_ROUGHNESS }, + { "emissive", PBRTYPE_EMISSIVE } + }; + + std::string user_data_string = user_data.asString(); + + if (!types.count(user_data_string)) + { + LL_WARNS() << "Unknown PBR channel " << user_data_string << LL_ENDL; + return; + } + + const S32 pbr_channel = types[user_data.asString()]; + + const std::string& spinner_name = ctrl->getName(); + const float value = ctrl->getValue().asReal(); + + if (LLStringUtil::startsWith(spinner_name, "gltfTextureScaleU")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mScale.mV[VX] = value; + }); + } + else if (LLStringUtil::startsWith(spinner_name, "gltfTextureScaleV")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mScale.mV[VY] = value; + }); + } + else if (LLStringUtil::startsWith(spinner_name, "gltfTextureRotation")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mRotation = value * DEG_TO_RAD; + }); + } + else if (LLStringUtil::startsWith(spinner_name, "gltfTextureOffsetU")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mOffset.mV[VX] = value; + }); + } + else if (LLStringUtil::startsWith(spinner_name, "gltfTextureOffsetV")) + { + updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform) + { + new_transform->mOffset.mV[VY] = value; + }); + } +} + +// selection inside the texture/material picker changed +void FSPanelFace::onTextureSelectionChanged(const std::string& which_control) +{ + LL_DEBUGS("Materials") << "control " << which_control << LL_ENDL; + + LLTextureCtrl* texture_ctrl = findChild(which_control); + if (texture_ctrl) + { + LLInventoryItem* itemp = gInventory.getItem(texture_ctrl->getImageItemID()); + if (!itemp) + { + // no inventory asset available, i.e. could be "Blank" + return; + } + + LL_WARNS("Materials") << "item inventory id " << itemp->getUUID() << " - item asset " << itemp->getAssetUUID() << LL_ENDL; + + LLUUID obj_owner_id; + std::string obj_owner_name; + LLSelectMgr::instance().selectGetOwner(obj_owner_id, obj_owner_name); + + LLSaleInfo sale_info; + LLSelectMgr::instance().selectGetSaleInfo(sale_info); + + bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this texture? + bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this texture? + bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply texture belong to the agent? + bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply texture not for sale? + + if (can_copy && can_transfer) + { + texture_ctrl->setCanApply(true, true); + return; + } + + // if texture has (no-transfer) attribute it can be applied only for object which we own and is not for sale + texture_ctrl->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale); + + if (gSavedSettings.getBOOL("TextureLivePreview")) + { + LLNotificationsUtil::add("LivePreviewUnavailable"); + } + } +} + +// selection inside the texture/material picker changed +void FSPanelFace::onPbrSelectionChanged(LLInventoryItem* itemp) +{ + LLUUID obj_owner_id; + std::string obj_owner_name; + LLSelectMgr::instance().selectGetOwner(obj_owner_id, obj_owner_name); + + LLSaleInfo sale_info; + LLSelectMgr::instance().selectGetSaleInfo(sale_info); + + bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this material? + bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this material? + bool can_modify = itemp->getPermissions().allowOperationBy(PERM_MODIFY, gAgentID); // do we have perm to transfer this material? + bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply material belong to the agent? + bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply material not for sale? + + if (can_copy && can_transfer && can_modify) + { + mMaterialCtrlPBR->setCanApply(true, true); + return; + } + + // if material has (no-transfer) attribute it can be applied only for object which we own and is not for sale + mMaterialCtrlPBR->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale); + + if (gSavedSettings.getBOOL("TextureLivePreview")) + { + LLNotificationsUtil::add("LivePreviewUnavailablePBR"); + } +} + +bool FSPanelFace::isIdenticalPlanarTexgen() +{ + LLTextureEntry::e_texgen selected_texgen = LLTextureEntry::TEX_GEN_DEFAULT; + bool identical_texgen = false; + LLSelectedTE::getTexGen(selected_texgen, identical_texgen); + return (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR)); +} + +void FSPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical_face) +{ + struct LLSelectedTEGetFace : public LLSelectedTEGetFunctor + { + LLFace* get(LLViewerObject* object, S32 te) + { + return (object->mDrawable) ? object->mDrawable->getFace(te): NULL; + } + } get_te_face_func; + + identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return, false, (LLFace*)nullptr); +} + +void FSPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face) +{ + LLGLenum image_format{ GL_RGB }; + struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor + { + LLGLenum get(LLViewerObject* object, S32 te_index) + { + LLViewerTexture* image = object->getTEImage(te_index); + return image ? image->getPrimaryFormat() : GL_RGB; + } + } get_glenum; + + identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_glenum, image_format); + image_format_to_return = image_format; +} + +void FSPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical) +{ + struct LLSelectedTEGetTexId : public LLSelectedTEGetFunctor + { + LLUUID get(LLViewerObject* object, S32 te_index) + { + LLTextureEntry *te = object->getTE(te_index); + if (te) + { + if ((te->getID() == IMG_USE_BAKED_EYES) || (te->getID() == IMG_USE_BAKED_HAIR) || (te->getID() == IMG_USE_BAKED_HEAD) || (te->getID() == IMG_USE_BAKED_LOWER) || (te->getID() == IMG_USE_BAKED_SKIRT) || (te->getID() == IMG_USE_BAKED_UPPER) + || (te->getID() == IMG_USE_BAKED_LEFTARM) || (te->getID() == IMG_USE_BAKED_LEFTLEG) || (te->getID() == IMG_USE_BAKED_AUX1) || (te->getID() == IMG_USE_BAKED_AUX2) || (te->getID() == IMG_USE_BAKED_AUX3)) + { + return te->getID(); + } + } + + LLUUID id; + LLViewerTexture* image = object->getTEImage(te_index); + if (image) + { + id = image->getID(); + } + + if (!id.isNull() && LLViewerMedia::getInstance()->textureHasMedia(id)) + { + if (te) + { + LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; + if(!tex) + { + tex = LLViewerFetchedTexture::sDefaultImagep; + } + if (tex) + { + id = tex->getID(); + } + } + } + return id; + } + } func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, id ); +} + +void FSPanelFace::LLSelectedTEMaterial::getCurrent(LLMaterialPtr& material_ptr, bool& identical_material) +{ + struct MaterialFunctor : public LLSelectedTEGetFunctor + { + LLMaterialPtr get(LLViewerObject* object, S32 te_index) + { + return object->getTEref(te_index).getMaterialParams(); + } + } func; + + identical_material = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_ptr); +} + +void FSPanelFace::LLSelectedTEMaterial::getMaxSpecularRepeats(F32& repeats, bool& identical) +{ + struct LLSelectedTEGetMaxSpecRepeats : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + LLMaterial* mat = object->getTEref(face).getMaterialParams().get(); + U32 s_axis = VX; + U32 t_axis = VY; + F32 repeats_s = 1.0f; + F32 repeats_t = 1.0f; + if (mat) + { + mat->getSpecularRepeat(repeats_s, repeats_t); + repeats_s /= object->getScale().mV[s_axis]; + repeats_t /= object->getScale().mV[t_axis]; + } + return llmax(repeats_s, repeats_t); + } + + } max_spec_repeats_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_spec_repeats_func, repeats); +} + +void FSPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool& identical) +{ + struct LLSelectedTEGetMaxNormRepeats : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + LLMaterial* mat = object->getTEref(face).getMaterialParams().get(); + U32 s_axis = VX; + U32 t_axis = VY; + F32 repeats_s = 1.0f; + F32 repeats_t = 1.0f; + if (mat) + { + mat->getNormalRepeat(repeats_s, repeats_t); + repeats_s /= object->getScale().mV[s_axis]; + repeats_t /= object->getScale().mV[t_axis]; + } + return llmax(repeats_s, repeats_t); + } + + } max_norm_repeats_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_norm_repeats_func, repeats); +} + +void FSPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, const bool diffuse_texture_has_alpha) +{ + struct LLSelectedTEGetDiffuseAlphaMode : public LLSelectedTEGetFunctor + { + LLSelectedTEGetDiffuseAlphaMode() : _isAlpha(false) {} + LLSelectedTEGetDiffuseAlphaMode(bool diffuse_texture_has_alpha) : _isAlpha(diffuse_texture_has_alpha) {} + virtual ~LLSelectedTEGetDiffuseAlphaMode() {} + + U8 get(LLViewerObject* object, S32 face) + { + U8 diffuse_mode = _isAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + LLTextureEntry* tep = object->getTE(face); + if (tep) + { + LLMaterial* mat = tep->getMaterialParams().get(); + if (mat) + { + diffuse_mode = mat->getDiffuseAlphaMode(); + } + } + + return diffuse_mode; + } + + bool _isAlpha; // whether or not the diffuse texture selected contains alpha information + } get_diff_mode(diffuse_texture_has_alpha); + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode); +} + +void FSPanelFace::LLSelectedTE::getObjectScaleS(F32& scale_s, bool& identical) +{ + struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + U32 s_axis = VX; + U32 t_axis = VY; + LLPrimitive::getTESTAxes(face, &s_axis, &t_axis); + return object->getScale().mV[s_axis]; + } + + } scale_s_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &scale_s_func, scale_s ); +} + +void FSPanelFace::LLSelectedTE::getObjectScaleT(F32& scale_t, bool& identical) +{ + struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + U32 s_axis = VX; + U32 t_axis = VY; + LLPrimitive::getTESTAxes(face, &s_axis, &t_axis); + return object->getScale().mV[t_axis]; + } + + } scale_t_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &scale_t_func, scale_t ); +} + +void FSPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identical) +{ + struct LLSelectedTEGetMaxDiffuseRepeats : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + U32 s_axis = VX; + U32 t_axis = VY; + LLPrimitive::getTESTAxes(face, &s_axis, &t_axis); + F32 repeats_s = object->getTEref(face).mScaleS / object->getScale().mV[s_axis]; + F32 repeats_t = object->getTEref(face).mScaleT / object->getScale().mV[t_axis]; + return llmax(repeats_s, repeats_t); + } + + } max_diff_repeats_func; + + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats ); +} + +void FSPanelFace::onClickMapsSync() +{ + getState(); + if (gSavedSettings.getBOOL("SyncMaterialSettings")) + { + alignMaterialsProperties(); + } +} + +// used to be called from two places but onCommitFlip() now does it a different way +// so we end up with this still being a function but strictly it could be moved +// into onClickMapsSync() -Zi +void FSPanelFace::alignMaterialsProperties() +{ + // FIRE-11911: Synchronize materials doesn't work with planar textures + // Don't even try to do the alignment if we wind up here and planar is enabled. + if (mCheckPlanarAlign->getValue().asBoolean()) + { + return; + } + // FIRE-11911 + + F32 tex_scale_u = getCurrentTextureScaleU(); + F32 tex_scale_v = getCurrentTextureScaleV(); + F32 tex_offset_u = getCurrentTextureOffsetU(); + F32 tex_offset_v = getCurrentTextureOffsetV(); + F32 tex_rot = getCurrentTextureRot(); + + // FIRE-12275: Material offset not working correctly + // Since the server cannot store negative offsets for materials + // textures, we normalize them to equivalent positive values here. + tex_offset_u = (tex_offset_u < 0.0) ? 1.0 + tex_offset_u : tex_offset_u; + tex_offset_v = (tex_offset_v < 0.0) ? 1.0 + tex_offset_v : tex_offset_v; + // FIRE-12275 + + // FIRE-12831: Negative rotations revert to zero + // The same goes for rotations as for offsets. + tex_rot = (tex_rot < 0.0) ? 360.0 + tex_rot : tex_rot; + // FIRE-12831 + + mCtrlShinyScaleU->setValue(tex_scale_u); + mCtrlShinyScaleV->setValue(tex_scale_v); + mCtrlShinyOffsetU->setValue(tex_offset_u); + mCtrlShinyOffsetV->setValue(tex_offset_v); + mCtrlShinyRot->setValue(tex_rot); + + // What is this abomination!? -Zi + LLSelectedTEMaterial::setSpecularRepeatX(this, tex_scale_u); + LLSelectedTEMaterial::setSpecularRepeatY(this, tex_scale_v); + LLSelectedTEMaterial::setSpecularOffsetX(this, tex_offset_u); + LLSelectedTEMaterial::setSpecularOffsetY(this, tex_offset_v); + LLSelectedTEMaterial::setSpecularRotation(this, tex_rot * DEG_TO_RAD); + + mCtrlBumpyScaleU->setValue(tex_scale_u); + mCtrlBumpyScaleV->setValue(tex_scale_v); + mCtrlBumpyOffsetU->setValue(tex_offset_u); + mCtrlBumpyOffsetV->setValue(tex_offset_v); + mCtrlBumpyRot->setValue(tex_rot); + + // What is this abomination!? -Zi + LLSelectedTEMaterial::setNormalRepeatX(this, tex_scale_u); + LLSelectedTEMaterial::setNormalRepeatY(this, tex_scale_v); + LLSelectedTEMaterial::setNormalOffsetX(this, tex_offset_u); + LLSelectedTEMaterial::setNormalOffsetY(this, tex_offset_v); + LLSelectedTEMaterial::setNormalRotation(this, tex_rot * DEG_TO_RAD); +} + +void FSPanelFace::onCommitFlip(const LLSD& user_data) +{ + LL_WARNS() << "onCommitFlip" << LL_ENDL; + std::string control_name = user_data.asString(); + if (control_name.empty()) + { + LL_WARNS() << "empty user data!" << LL_ENDL; + return; + } + + LL_WARNS() << "control name: " << control_name << LL_ENDL; + + LLSpinCtrl* spinner = findChild(control_name); + if (spinner) + { + // TODO: compensate for normal/specular map doubling of values in planar mapping mode -Zi + F32 value = -(spinner->getValue().asReal()); + spinner->setValue(value); + spinner->forceEditorCommit(); + } + else + { + LL_WARNS() << "spinner not found: " << control_name << LL_ENDL; + } +} + +void FSPanelFace::changePrecision(S32 decimal_precision) +{ + mCtrlTexScaleU->setPrecision(decimal_precision); + mCtrlTexScaleV->setPrecision(decimal_precision); + mCtrlBumpyScaleU->setPrecision(decimal_precision); + mCtrlBumpyScaleV->setPrecision(decimal_precision); + mCtrlShinyScaleU->setPrecision(decimal_precision); + mCtrlShinyScaleV->setPrecision(decimal_precision); + mCtrlTexOffsetU->setPrecision(decimal_precision); + mCtrlTexOffsetV->setPrecision(decimal_precision); + mCtrlBumpyOffsetU->setPrecision(decimal_precision); + mCtrlBumpyOffsetV->setPrecision(decimal_precision); + mCtrlShinyOffsetU->setPrecision(decimal_precision); + mCtrlShinyOffsetV->setPrecision(decimal_precision); + mCtrlTexRot->setPrecision(decimal_precision); + mCtrlBumpyRot->setPrecision(decimal_precision); + mCtrlShinyRot->setPrecision(decimal_precision); + mCtrlRpt->setPrecision(decimal_precision); + // TODO: add PBR spinners -Zi +} + +void FSPanelFace::onShowFindAllButton(LLUICtrl* ctrl, const LLSD& user_data) +{ + findChildView(user_data.asStringRef())->setVisible(true); +} + +void FSPanelFace::onHideFindAllButton(LLUICtrl* ctrl, const LLSD& user_data) +{ + findChildView(user_data.asStringRef())->setVisible(false); +} + +// Find all faces with same texture +void FSPanelFace::onClickBtnSelectSameTexture(const LLUICtrl* ctrl, const LLSD& user_data) +{ + std::unordered_set objects; + + // get a list of all linksets where at least one face is selected + for (auto iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) + { + objects.insert((*iter)->getObject()->getRootEdit()); + } + + // clean out the selection + LLSelectMgr::getInstance()->deselectAll(); + + // select all faces of all linksets that were found before + LLObjectSelectionHandle handle; + for(auto objectp : objects) + { + handle = LLSelectMgr::getInstance()->selectObjectAndFamily(objectp, true, false); + } + + // get the texture channel we are interested in - using the first letter is sufficient + // and makes things faster in the if () blocks + char channel = user_data.asStringRef()[0]; + + // grab the texture ID from the texture selector + LLTextureCtrl* texture_control = mTextureCtrl; + if (channel == 'n') + { + texture_control = mBumpyTextureCtrl; + } + else if (channel == 's') + { + texture_control = mShinyTextureCtrl; + } + else if (channel == 'g') + { + texture_control = mMaterialCtrlPBR; + } + + LLUUID id = texture_control->getImageAssetID(); + + // go through all selected links in all selected linksets + for (auto iter = handle->begin(); iter != handle->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* objectp = node->getObject(); + + U8 te_count = objectp->getNumTEs(); + + for (U8 i = 0; i < te_count; i++) + { + LLUUID image_id; + if (channel == 'd') + { + image_id = objectp->getTEImage(i)->getID(); + } + else if (channel == 'g') + { + image_id = objectp->getRenderMaterialID(i); + } + else + { + const LLMaterialPtr mat = objectp->getTEref(i).getMaterialParams(); + if (mat.notNull()) + { + if (channel == 'n') + { + image_id = mat->getNormalID(); + } + else if (channel == 's') + { + image_id = mat->getSpecularID(); + } + } + } + + // deselect all faces that use a different texture UUID + if (image_id != id) + { + objectp->setTESelected(i, false); + node->selectTE(i, false); + } + } + } +} + +// +// convenience functions around tab containers -Zi +// + +S32 FSPanelFace::getCurrentMaterialType() const +{ + const std::string& tab_name = mTabsPBRMatMedia->getCurrentPanel()->getName(); + + if (tab_name == "panel_material_type_pbr") + { + return MATMEDIA_PBR; + } + else if (tab_name == "panel_material_type_media") + { + return MATMEDIA_MEDIA; + } + return MATMEDIA_MATERIAL; +} + +S32 FSPanelFace::getCurrentMatChannel() const +{ + const std::string& tab_name = mTabsMatChannel->getCurrentPanel()->getName(); + + if (tab_name == "panel_blinn_phong_normal") + { + return MATTYPE_NORMAL; + } + if (tab_name == "panel_blinn_phong_specular") + { + return MATTYPE_SPECULAR; + } + return MATTYPE_DIFFUSE; +} + +S32 FSPanelFace::getCurrentPBRChannel() const +{ + const std::string& tab_name = mTabsPBRChannel->getCurrentPanel()->getName(); + + if (tab_name == "panel_pbr_transforms_base_color") + { + return PBRTYPE_BASE_COLOR; + } + if (tab_name == "panel_pbr_transforms_normal") + { + return PBRTYPE_NORMAL; + } + if (tab_name == "panel_pbr_transforms_metallic") + { + return PBRTYPE_METALLIC_ROUGHNESS; // TODO: we use specular editor color for now -Zi + } + if (tab_name == "panel_pbr_transforms_emissive") + { + return PBRTYPE_EMISSIVE; // TODO: "emissive" has no defined editor color yet -Zi + } + return PBRTYPE_RENDER_MATERIAL_ID; +} + +void FSPanelFace::selectMaterialType(S32 material_type) +{ + if (material_type == MATMEDIA_PBR) + { + mTabsPBRMatMedia->selectTabByName("panel_material_type_pbr"); + } + else if (material_type == MATMEDIA_MEDIA) + { + mTabsPBRMatMedia->selectTabByName("panel_material_type_media"); + } + else + { + mTabsPBRMatMedia->selectTabByName("panel_material_type_blinn_phong"); + } + onMatTabChange(); // set up relative to active tab +} + +void FSPanelFace::selectMatChannel(S32 mat_channel) +{ + if (mat_channel == MATTYPE_NORMAL) + { + mTabsMatChannel->selectTabByName("panel_blinn_phong_normal"); + } + else if (mat_channel == MATTYPE_SPECULAR) + { + mTabsMatChannel->selectTabByName("panel_blinn_phong_specular"); + } + else + { + mTabsMatChannel->selectTabByName("panel_blinn_phong_diffuse"); + } +} + +void FSPanelFace::selectPBRChannel(S32 pbr_channel) +{ + if (pbr_channel == PBRTYPE_NORMAL) + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_base_color"); + } + else if (pbr_channel == PBRTYPE_BASE_COLOR) + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_normal"); + } + else if (pbr_channel == PBRTYPE_METALLIC_ROUGHNESS) + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_metallic"); + } + else if (pbr_channel == PBRTYPE_EMISSIVE) + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_emissive"); + } + else + { + mTabsMatChannel->selectTabByName("panel_pbr_transforms_all"); + } +} diff --git a/indra/newview/fspanelface.h b/indra/newview/fspanelface.h new file mode 100644 index 0000000000..cdadee0e86 --- /dev/null +++ b/indra/newview/fspanelface.h @@ -0,0 +1,806 @@ +/** + * @file fspanelface.h + * @brief Consolidated materials/texture panel in the tools floater + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2024, Zi Ree@Second Life + * + * 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 FS_FSPANELFACE_H +#define FS_FSPANELFACE_H + +#include "v4color.h" +#include "llpanel.h" +#include "llgltfmaterial.h" +#include "llmaterial.h" +#include "llmaterialmgr.h" +#include "lltextureentry.h" +#include "llselectmgr.h" + +#include + +class LLButton; +class LLCheckBoxCtrl; +class LLColorSwatchCtrl; +class LLComboBox; +class LLInventoryItem; +class LLLineEditor; +class LLRadioGroup; +class LLSpinCtrl; +class LLTextBox; +class LLTextureCtrl; +class LLUICtrl; +class LLViewerObject; +class LLFloater; +class LLMaterialID; +class LLMediaCtrl; +class LLMenuButton; + +class PBRPickerAgentListener; +class PBRPickerObjectListener; + +class LLTabContainer; + +// Represents an edit for use in replicating the op across one or more materials in the selection set. +// +// The apply function optionally performs the edit which it implements +// as a functor taking Data that calls member func MaterialFunc taking SetValueType +// on an instance of the LLMaterial class. +// +// boost who? +// +template< + typename DataType, + typename SetValueType, + void (LLMaterial::*MaterialEditFunc)(SetValueType data) > +class FSMaterialEditFunctor +{ +public: + FSMaterialEditFunctor(const DataType& data) : _data(data) {} + virtual ~FSMaterialEditFunctor() {} + virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); } + DataType _data; +}; + +template< + typename DataType, + DataType (LLMaterial::*MaterialGetFunc)() > +class FSMaterialGetFunctor +{ +public: + FSMaterialGetFunctor() {} + virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); } +}; + +template< + typename DataType, + DataType (LLTextureEntry::*TEGetFunc)() > +class FSTEGetFunctor +{ +public: + FSTEGetFunctor() {} + virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); } +}; + +// +// main class +// + +class FSPanelFace : public LLPanel +{ +public: + FSPanelFace(); + virtual ~FSPanelFace(); + + virtual BOOL postBuild(); + + void refresh(); + void refreshMedia(); + void unloadMedia(); + void changePrecision(S32 decimal_precision); // Adjustable decimal precision + + static void onMaterialOverrideReceived(const LLUUID& object_id, S32 side); + + /*virtual*/ void onVisibilityChange(BOOL new_visibility); + /*virtual*/ void draw(); + + LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material); + + LLRender::eTexIndex getTextureChannelToEdit(); + LLRender::eTexIndex getTextureDropChannel(); + + LLGLTFMaterial::TextureInfo getPBRDropChannel(); + +protected: + void navigateToTitleMedia(const std::string url); + bool selectedMediaEditable(); + void clearMediaSettings(); + void updateMediaSettings(); + void updateMediaTitle(); + + void getState(); + + void sendTexture(); // applies and sends texture + void sendTextureInfo(); // applies and sends texture scale, offset, etc. + void sendColor(); // applies and sends color + void sendAlpha(); // applies and sends transparency + void sendBump(U32 bumpiness); // applies and sends bump map + void sendTexGen(); // applies and sends bump map + void sendShiny(U32 shininess); // applies and sends shininess + void sendFullbright(); // applies and sends full bright + void sendGlow(); + void alignTextureLayer(); + + void updateCopyTexButton(); + + // + // UI Callbacks + // + + // common controls and parameters for Blinn-Phong and PBR + void onCopyFaces(); // Extended copy & paste buttons + void onPasteFaces(); + void onCommitGlow(); + void onCommitRepeatsPerMeter(); + + // Blinn-Phong alpha parameters + void onCommitAlpha(); + void onCommitAlphaMode(); + void onCommitMaterialMaskCutoff(); + void onCommitFullbright(); + + // Blinn-Phong texture transforms and controls + void onCommitTexGen(); + void onCommitPlanarAlign(); + void onCommitBump(); + void onCommitShiny(); + void onCommitTextureScaleX(); + void onCommitTextureScaleY(); + void onCommitTextureOffsetX(); + void onCommitTextureOffsetY(); + void onCommitTextureRot(); + void onCommitMaterialBumpyScaleX(); + void onCommitMaterialBumpyScaleY(); + void onCommitMaterialBumpyOffsetX(); + void onCommitMaterialBumpyOffsetY(); + void onCommitMaterialBumpyRot(); + void onCommitMaterialShinyScaleX(); + void onCommitMaterialShinyScaleY(); + void onCommitMaterialShinyOffsetX(); + void onCommitMaterialShinyOffsetY(); + void onCommitMaterialShinyRot(); + void onCommitMaterialGloss(); + void onCommitMaterialEnv(); + + // Blinn-Phong Diffuse tint color swatch + void onCommitColor(); + void onCancelColor(); + void onSelectColor(); + + // Blinn-Phong Diffuse texture swatch + void onCommitTexture(const LLUICtrl* ctrl, const LLSD& data); + void onCancelTexture(); + BOOL onDragTexture(LLInventoryItem* item); // this function is to return TRUE if the drag should succeed. + void onCloseTexturePicker(const LLSD& data); + + // Blinn-Phong Normal texture swatch + void onCommitNormalTexture(const LLUICtrl* ctrl, const LLSD& data); + void onCancelNormalTexture(); + + // Blinn-Phong Specular texture swatch + void onCommitSpecularTexture(const LLUICtrl* ctrl, const LLSD& data); + void onCancelSpecularTexture(); + + // Blinn-Phong Specular tint color swatch + void onCommitShinyColor(); + void onCancelShinyColor(); + void onSelectShinyColor(); + + // Texture alignment and maps synchronization + void onClickAutoFix(); + void onAlignTexture(); + void onClickMapsSync(); + + /* + * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object. + * If agent selects texture which is not allowed to be applied for the currently selected object, + * all controls of the floater texture picker which allow to apply the texture will be disabled. + */ + void onTextureSelectionChanged(const std::string& which_control); + + // Media + void onClickBtnEditMedia(); + void onClickBtnDeleteMedia(); + void onClickBtnAddMedia(); + + void alignMaterialsProperties(); + + // + // PBR + // + + // PBR Material + void onCommitPbr(); + void onCancelPbr(); + void onSelectPbr(); + BOOL onDragPbr(LLInventoryItem* item); // this function is to return TRUE if the drag should succeed. + + void onPbrSelectionChanged(LLInventoryItem* itemp); + void onClickBtnSavePBR(); + + void updatePBROverrideDisplay(); + + // PBR texture maps + void onCommitPbr(const LLUICtrl* pbr_ctrl); + void onCancelPbr(const LLUICtrl* pbr_ctrl); + void onSelectPbr(const LLUICtrl* pbr_ctrl); + + void getGLTFMaterial(LLGLTFMaterial* mat); + + // + // other + // + + bool deleteMediaConfirm(const LLSD& notification, const LLSD& response); + bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response); + + // Make UI reflect state of currently selected material (refresh) + // and UI mode (e.g. editing normal map v diffuse map) + // + // @param force_set_values forces spinners to set value even if they are focused + void updateUI(bool force_set_values = false); + + // Convenience func to determine if all faces in selection have + // identical planar texgen settings during edits + // + bool isIdenticalPlanarTexgen(); + + // Callback funcs for individual controls + // + static void syncRepeatX(FSPanelFace* self, F32 scaleU); + static void syncRepeatY(FSPanelFace* self, F32 scaleV); + static void syncOffsetX(FSPanelFace* self, F32 offsetU); + static void syncOffsetY(FSPanelFace* self, F32 offsetV); + static void syncMaterialRot(FSPanelFace* self, F32 rot, int te = -1); + + // unify all GLTF spinners with no switching around required -Zi + void onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_data); + + void onClickBtnSelectSameTexture(const LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture + void onShowFindAllButton(LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture + void onHideFindAllButton(LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture + +public: // needs to be accessible to selection manager + void onCopyColor(); // records all selected faces + void onPasteColor(); // to specific face + void onPasteColor(LLViewerObject* objectp, S32 te); // to specific face + void onCopyTexture(); + void onPasteTexture(); + void onPasteTexture(LLViewerObject* objectp, S32 te); + +protected: + // + // Constant definitions for tabs and combo boxes + // Must match the commbobox definitions in panel_tools_texture.xml // Not anymore -Zi + // + static constexpr S32 MATMEDIA_MATERIAL = 0; // Material + static constexpr S32 MATMEDIA_PBR = 1; // PBR + static constexpr S32 MATMEDIA_MEDIA = 2; // Media + + static constexpr S32 MATTYPE_DIFFUSE = 0; // Diffuse material texture + static constexpr S32 MATTYPE_NORMAL = 1; // Normal map + static constexpr S32 MATTYPE_SPECULAR = 2; // Specular map + + static constexpr S32 BUMPY_TEXTURE = 18; // use supplied normal map (index of "Use Texture" in combo box) + static constexpr S32 SHINY_TEXTURE = 4; // use supplied specular map (index of "Use Texture" in combo box) + + static constexpr S32 PBRTYPE_RENDER_MATERIAL_ID = 0; // Render Material ID + static constexpr S32 PBRTYPE_BASE_COLOR = 1; // PBR Base Color + static constexpr S32 PBRTYPE_METALLIC_ROUGHNESS = 2; // PBR Metallic + static constexpr S32 PBRTYPE_EMISSIVE = 3; // PBR Emissive + static constexpr S32 PBRTYPE_NORMAL = 4; // PBR Normal + static constexpr S32 PBRTYPE_COUNT = 5; // number of PBR map types + +public: + // public because ... functors? -Zi + void onCommitFlip(const LLSD& user_data); + + // Blinn-Phong texture transforms and controls + // public because ... functors? -Zi + LLSpinCtrl* mCtrlTexScaleU; + LLSpinCtrl* mCtrlTexScaleV; + LLSpinCtrl* mCtrlBumpyScaleU; + LLSpinCtrl* mCtrlBumpyScaleV; + LLSpinCtrl* mCtrlShinyScaleU; + LLSpinCtrl* mCtrlShinyScaleV; + LLSpinCtrl* mCtrlTexOffsetU; + LLSpinCtrl* mCtrlTexOffsetV; + LLSpinCtrl* mCtrlBumpyOffsetU; + LLSpinCtrl* mCtrlBumpyOffsetV; + LLSpinCtrl* mCtrlShinyOffsetU; + LLSpinCtrl* mCtrlShinyOffsetV; + LLSpinCtrl* mCtrlTexRot; + LLSpinCtrl* mCtrlBumpyRot; + LLSpinCtrl* mCtrlShinyRot; + + // Blinn-Phong texture transforms and controls + // public to give functors access -Zi + LLComboBox* mComboTexGen; + LLCheckBoxCtrl* mCheckPlanarAlign; + + // Tab controls + // public to give functors access -Zi + LLTabContainer* mTabsMatChannel; + void onMatTabChange(); + +private: + bool isAlpha() { return mIsAlpha; } + + // Update visibility of controls to match current UI mode + // (e.g. materials vs media editing) + // + // Do NOT call updateUI from within this function. + // + void updateVisibility(LLViewerObject* objectp = nullptr); + + // Convenience funcs to keep the visual flack to a minimum + // + LLUUID getCurrentNormalMap(); + LLUUID getCurrentSpecularMap(); + U32 getCurrentShininess(); + U32 getCurrentBumpiness(); + U8 getCurrentDiffuseAlphaMode(); + U8 getCurrentAlphaMaskCutoff(); + U8 getCurrentEnvIntensity(); + U8 getCurrentGlossiness(); + F32 getCurrentBumpyRot(); + F32 getCurrentBumpyScaleU(); + F32 getCurrentBumpyScaleV(); + F32 getCurrentBumpyOffsetU(); + F32 getCurrentBumpyOffsetV(); + F32 getCurrentShinyRot(); + F32 getCurrentShinyScaleU(); + F32 getCurrentShinyScaleV(); + F32 getCurrentShinyOffsetU(); + F32 getCurrentShinyOffsetV(); + + // map tab states to various values + // TODO: should be done with tab-change signals and flags, really + S32 getCurrentMaterialType() const; + S32 getCurrentMatChannel() const; + S32 getCurrentPBRChannel() const; + void selectMaterialType(S32 material_type); + void selectMatChannel(S32 mat_channel); + void selectPBRChannel(S32 pbr_channel); + + F32 getCurrentTextureRot(); + F32 getCurrentTextureScaleU(); + F32 getCurrentTextureScaleV(); + F32 getCurrentTextureOffsetU(); + F32 getCurrentTextureOffsetV(); + + // + // Build tool controls + // + + // private Tab controls + LLTabContainer* mTabsPBRMatMedia; + LLTabContainer* mTabsPBRChannel; + + // common controls and parameters for Blinn-Phong and PBR + LLButton* mBtnCopyFaces; + LLButton* mBtnPasteFaces; + LLSpinCtrl* mCtrlGlow; + LLSpinCtrl* mCtrlRpt; + + // Blinn-Phong alpha parameters + LLSpinCtrl* mCtrlColorTransp; // transparency = 1 - alpha + LLView* mColorTransPercent; + LLTextBox* mLabelAlphaMode; + LLComboBox* mComboAlphaMode; + LLSpinCtrl* mCtrlMaskCutoff; + LLCheckBoxCtrl* mCheckFullbright; + + // private Blinn-Phong texture transforms and controls + LLView* mLabelTexGen; + LLView* mLabelBumpiness; + LLComboBox* mComboBumpiness; + LLView* mLabelShininess; + LLComboBox* mComboShininess; + // others are above in the public section + LLSpinCtrl* mCtrlGlossiness; + LLSpinCtrl* mCtrlEnvironment; + + // Blinn-Phong Diffuse tint color swatch + LLColorSwatchCtrl* mColorSwatch; + + // Blinn-Phong Diffuse texture swatch + LLTextureCtrl* mTextureCtrl; + + // Blinn-Phong Normal texture swatch + LLTextureCtrl* mBumpyTextureCtrl; + + // Blinn-Phong Specular texture swatch + LLTextureCtrl* mShinyTextureCtrl; + + // Blinn-Phong Specular tint color swatch + LLColorSwatchCtrl* mShinyColorSwatch; + + // Texture alignment and maps synchronization + LLButton* mBtnAlignMedia; + LLButton* mBtnAlignTextures; + LLCheckBoxCtrl* mCheckSyncMaterials; + + // Media + LLButton* mBtnDeleteMedia; + LLButton* mBtnAddMedia; + LLMediaCtrl* mTitleMedia; + LLTextBox* mTitleMediaText; + + // PBR + LLTextureCtrl* mMaterialCtrlPBR; + LLColorSwatchCtrl* mBaseTintPBR; + LLTextureCtrl* mBaseTexturePBR; + LLTextureCtrl* mNormalTexturePBR; + LLTextureCtrl* mORMTexturePBR; + LLTextureCtrl* mEmissiveTexturePBR; + LLColorSwatchCtrl* mEmissiveTintPBR; + LLCheckBoxCtrl* mCheckDoubleSidedPBR; + LLSpinCtrl* mAlphaPBR; + LLTextBox* mLabelAlphaModePBR; + LLComboBox* mAlphaModePBR; + LLSpinCtrl* mMaskCutoffPBR; + LLSpinCtrl* mMetallicFactorPBR; + LLSpinCtrl* mRoughnessFactorPBR; + LLButton* mBtnSavePBR; + + struct + { + std::array mMap; + LLColor4 mBaseColorTint; + F32 mMetallic; + F32 mRoughness; + LLColor4 mEmissiveTint; + LLGLTFMaterial::AlphaMode mAlphaMode; + F32 mAlphaCutoff; + bool mDoubleSided; + } mPBRBaseMaterialParams; + + // map PBR material map types to glTF material types + LLGLTFMaterial::TextureInfo mPBRChannelToTextureInfo[PBRTYPE_COUNT] = + { + LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, // PBRTYPE_RENDER_MATERIAL_ID + LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR, // PBRTYPE_BASE_COLOR + LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, // PBRTYPE_METALLIC_ROUGHNESS + LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE, // PBRTYPE_EMISSIVE + LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL // PBRTYPE_NORMAL + }; + + // Dirty flags - taken from llmaterialeditor.cpp ... LL please put this in a .h! -Zi + U32 mUnsavedChanges; // flags to indicate individual changed parameters + + // Hey look everyone, a type-safe alternative to copy and paste! :) + // + + // Update material parameters by applying 'edit_func' to selected TEs + // + template< + typename DataType, + typename SetValueType, + void (LLMaterial::*MaterialEditFunc)(SetValueType data) > + static void edit(FSPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID()) + { + FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data); + struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor + { + LLSelectedTEEditMaterial(FSPanelFace* panel, FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp, const LLUUID &only_for_object_id) : _panel(panel), _edit(editp), _only_for_object_id(only_for_object_id) {} + virtual ~LLSelectedTEEditMaterial() {}; + virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material) + { + if (_edit && (_only_for_object_id.isNull() || _only_for_object_id == object->getID())) + { + LLMaterialPtr new_material = _panel->createDefaultMaterial(current_material); + llassert_always(new_material); + + // Determine correct alpha mode for current diffuse texture + // (i.e. does it have an alpha channel that makes alpha mode useful) + // + // _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329) + // need to get per-face answer to this question for sane alpha mode retention on updates. + // + bool is_alpha_face = object->isImageAlphaBlended(face); + + // need to keep this original answer for valid comparisons in logic below + // + U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + + U8 default_alpha_mode = original_default_alpha_mode; + + if (!current_material.isNull()) + { + default_alpha_mode = current_material->getDiffuseAlphaMode(); + } + + // Insure we don't inherit the default of blend by accident... + // this will be stomped by a legit request to change the alpha mode by the apply() below + // + new_material->setDiffuseAlphaMode(default_alpha_mode); + + // Do "It"! + // + _edit->apply(new_material); + + U32 new_alpha_mode = new_material->getDiffuseAlphaMode(); + LLUUID new_normal_map_id = new_material->getNormalID(); + LLUUID new_spec_map_id = new_material->getSpecularID(); + + if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face) + { + new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE); + } + + bool is_default_blend_mode = (new_alpha_mode == original_default_alpha_mode); + bool is_need_material = !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull(); + + if (!is_need_material) + { + LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL; + LLMaterialMgr::getInstance()->remove(object->getID(),face); + new_material = NULL; + } + else + { + LL_DEBUGS("Materials") << "Putting material on object " << object->getID() << " face " << face << ", material: " << new_material->asLLSD() << LL_ENDL; + LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material); + } + + object->setTEMaterialParams(face, new_material); + return new_material; + } + return NULL; + } + FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* _edit; + FSPanelFace *_panel; + const LLUUID & _only_for_object_id; + } editor(p, &edit, only_for_object_id); + LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor, te); + } + + template< + typename DataType, + typename ReturnType, + ReturnType (LLMaterial::* const MaterialGetFunc)() const > + static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType()) + { + DataType data_value = default_value; + struct GetTEMaterialVal : public LLSelectedTEGetFunctor + { + GetTEMaterialVal(DataType default_value) : _default(default_value) {} + virtual ~GetTEMaterialVal() {} + + DataType get(LLViewerObject* object, S32 face) + { + DataType ret = _default; + LLMaterialPtr material_ptr; + LLTextureEntry* tep = object ? object->getTE(face) : NULL; + if (tep) + { + material_ptr = tep->getMaterialParams(); + if (!material_ptr.isNull()) + { + ret = (material_ptr->*(MaterialGetFunc))(); + } + } + return ret; + } + DataType _default; + } GetFunc(default_value); + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value, has_tolerance, tolerance); + data_to_return = data_value; + } + + template< + typename DataType, + typename ReturnType, // some kids just have to different... + ReturnType (LLTextureEntry::* const TEGetFunc)() const > + static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType()) + { + DataType data_value = default_value; + struct GetTEVal : public LLSelectedTEGetFunctor + { + GetTEVal(DataType default_value) : _default(default_value) {} + virtual ~GetTEVal() {} + + DataType get(LLViewerObject* object, S32 face) { + LLTextureEntry* tep = object ? object->getTE(face) : NULL; + return tep ? ((tep->*(TEGetFunc))()) : _default; + } + DataType _default; + } GetTEValFunc(default_value); + identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value, has_tolerance, tolerance ); + data_to_return = data_value; + } + + // Update vis and enabling of specific subsets of controls based on material params + // (e.g. hide the spec controls if no spec texture is applied) + // + void updateShinyControls(bool is_setting_texture = false, bool mess_with_combobox = false); + void updateBumpyControls(bool is_setting_texture = false, bool mess_with_combobox = false); + void updateAlphaControls(); + void updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values); + + void updateSelectedGLTFMaterials(std::function func); + void updateGLTFTextureTransform(float value, U32 pbr_type, std::function edit); + + void setMaterialOverridesFromSelection(); + + bool mIsAlpha; + + LLSD mClipboardParams; + + LLSD mMediaSettings; + bool mNeedMediaTitle; + + class Selection + { + public: + void connect(); + + // Returns true if the selected objects or sides have changed since + // this was last called, and no object update is pending + bool update(); + + // Prevents update() returning true until the provided object is + // updated. Necessary to prevent controls updating when the mouse is + // held down. + void setDirty() { mChanged = true; }; + + // Callbacks + void onSelectionChanged() { mNeedsSelectionCheck = true; } + void onSelectedObjectUpdated(const LLUUID &object_id, S32 side); + + protected: + bool compareSelection(); + + bool mChanged = false; + + boost::signals2::scoped_connection mSelectConnection; + bool mNeedsSelectionCheck = true; + S32 mSelectedObjectCount = 0; + S32 mSelectedTECount = 0; + LLUUID mSelectedObjectID; + S32 mLastSelectedSide = -1; + }; + + static Selection sMaterialOverrideSelection; + + std::unique_ptr mAgentInventoryListener; + std::unique_ptr mVOInventoryListener; + +public: + #if defined(FS_DEF_GET_MAT_STATE) + #undef FS_DEF_GET_MAT_STATE + #endif + + #if defined(FS_DEF_GET_TE_STATE) + #undef FS_DEF_GET_TE_STATE + #endif + + #if defined(FS_DEF_EDIT_MAT_STATE) + FS_DEF_EDIT_MAT_STATE + #endif + + // Accessors for selected TE material state + // + #define FS_DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue,HasTolerance,Tolerance) \ + static void MaterialMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance) \ + { \ + getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance); \ + } + + // Mutators for selected TE material + // + #define FS_DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc) \ + static void MaterialMemberFunc(FSPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID()) \ + { \ + edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p, data, te, only_for_object_id); \ + } + + // Accessors for selected TE state proper (legacy settings etc) + // + #define FS_DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue,HasTolerance,Tolerance) \ + static void TexEntryMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance) \ + { \ + getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance); \ + } + + class LLSelectedTEMaterial + { + public: + static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material); + static void getMaxSpecularRepeats(F32& repeats, bool& identical); + static void getMaxNormalRepeats(F32& repeats, bool& identical); + static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha); + + FS_DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null) + FS_DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f, true, 0.001f) + + FS_DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f, true, 0.001f) + FS_DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f, true, 0.001f) + + FS_DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode); + FS_DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff); + + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX); + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY); + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX); + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY); + FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation); + + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX); + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY); + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX); + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY); + FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation); + + FS_DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity); + FS_DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent); + + FS_DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID); + FS_DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID); + FS_DEF_EDIT_MAT_STATE(LLColor4U, const LLColor4U&,setSpecularLightColor); + }; + + class LLSelectedTE + { + public: + static void getFace(class LLFace*& face_to_return, bool& identical_face); + static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face); + static void getTexId(LLUUID& id, bool& identical); + static void getObjectScaleS(F32& scale_s, bool& identical); + static void getObjectScaleT(F32& scale_t, bool& identical); + static void getMaxDiffuseRepeats(F32& repeats, bool& identical); + + FS_DEF_GET_TE_STATE(U8,U8,getBumpmap,0, false, 0) + FS_DEF_GET_TE_STATE(U8,U8,getShiny,0, false, 0) + FS_DEF_GET_TE_STATE(U8,U8,getFullbright,0, false, 0) + FS_DEF_GET_TE_STATE(F32,F32,getRotation,0.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f) + FS_DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT) + FS_DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black); + }; +}; + +#endif diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 1a1c42bcb3..047bf650ea 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -102,7 +102,6 @@ #include "llworld.h" #include "llworldmap.h" #include "stringize.h" -#include "boost/foreach.hpp" #include "llcorehttputil.h" #include "lluiusage.h" // [RLVa:KB] - Checked: 2011-11-04 (RLVa-1.4.4a) @@ -1675,23 +1674,27 @@ void LLAgent::pitch(F32 angle) LLVector3 skyward = getReferenceUpVector(); - // SL-19286 Avatar is upside down when viewed from below - // after left-clicking the mouse on the avatar and dragging down - // - // The issue is observed on angle below 10 degrees - const F32 look_down_limit = 179.f * DEG_TO_RAD; - const F32 look_up_limit = 10.f * DEG_TO_RAD; - - F32 angle_from_skyward = acos(mFrameAgent.getAtAxis() * skyward); - // clamp pitch to limits - if ((angle >= 0.f) && (angle_from_skyward + angle > look_down_limit)) + if (angle >= 0.f) { - angle = look_down_limit - angle_from_skyward; + const F32 look_down_limit = 179.f * DEG_TO_RAD; + F32 angle_from_skyward = acos(mFrameAgent.getAtAxis() * skyward); + if (angle_from_skyward + angle > look_down_limit) + { + angle = look_down_limit - angle_from_skyward; + } } - else if ((angle < 0.f) && (angle_from_skyward + angle < look_up_limit)) + else if (angle < 0.f) { - angle = look_up_limit - angle_from_skyward; + const F32 look_up_limit = 5.f * DEG_TO_RAD; + const LLVector3& viewer_camera_pos = LLViewerCamera::getInstance()->getOrigin(); + LLVector3 agent_focus_pos = getPosAgentFromGlobal(gAgentCamera.calcFocusPositionTargetGlobal()); + LLVector3 look_dir = agent_focus_pos - viewer_camera_pos; + F32 angle_from_skyward = angle_between(look_dir, skyward); + if (angle_from_skyward + angle < look_up_limit) + { + angle = look_up_limit - angle_from_skyward; + } } if (fabs(angle) > 1e-4) @@ -2806,7 +2809,7 @@ void LLAgent::endAnimationUpdateUI() skip_list.insert(LLFloaterReg::findInstance("stats")); } // //FIRE-6385: Show all script dialogs still after leaving mouselook - BOOST_FOREACH(LLFloater *tmp, LLFloaterReg::getFloaterList("script_floater")) + for (LLFloater *tmp : LLFloaterReg::getFloaterList("script_floater")) { skip_list.insert(tmp); } @@ -2825,7 +2828,7 @@ void LLAgent::endAnimationUpdateUI() //LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance("im_container"); //LLFloaterIMContainer::floater_list_t conversations; //im_box->getDetachedConversationFloaters(conversations); - //BOOST_FOREACH(LLFloater* conversation, conversations) + //for (LLFloater* conversation : conversations) //{ // LL_INFOS() << "skip_list.insert(session_floater): " << conversation->getTitle() << LL_ENDL; // skip_list.insert(conversation); @@ -2981,7 +2984,7 @@ void LLAgent::endAnimationUpdateUI() skip_list.insert(LLFloaterReg::findInstance("stats")); } // //FIRE-6385: Show all script dialogs still when entering mouselook - BOOST_FOREACH(LLFloater *tmp, LLFloaterReg::getFloaterList("script_floater")) + for (LLFloater* tmp : LLFloaterReg::getFloaterList("script_floater")) { skip_list.insert(tmp); } @@ -5159,14 +5162,14 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id) } // [/RLVa:KB] - // FIRE-7273: Typing does not stop after using Cmd Line tph - if (landmark_asset_id.isNull()) - { - // This might mean a local TP, so pro-actively stop typing - gAgent.stopTyping(); - } - // - + if (landmark_asset_id.isNull()) + { + gAgentCamera.resetView(); + // FIRE-7273: Typing does not stop after using Cmd Line tph + // This might mean a local TP, so pro-actively stop typing + gAgent.stopTyping(); + // + } mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id)); startTeleportRequest(); } diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 120506d3b5..abd1f6be0b 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -64,7 +64,7 @@ class LLTeleportRequest; -typedef boost::shared_ptr LLTeleportRequestPtr; +typedef std::shared_ptr LLTeleportRequestPtr; //-------------------------------------------------------------------- // Types @@ -134,7 +134,7 @@ public: private: bool mInitialized; bool mFirstLogin; - boost::shared_ptr mListener; + std::shared_ptr mListener; //-------------------------------------------------------------------- // Session diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index d1c4cb3965..b470f98c10 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -1879,7 +1879,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) head_offset.clearVec(); F32 fixup; - if (gAgentAvatarp->hasPelvisFixup(fixup)) + if (gAgentAvatarp->hasPelvisFixup(fixup) && !gAgentAvatarp->isSitting()) { head_offset[VZ] -= fixup; } diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index d5027b17ea..f11026d595 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -1806,10 +1806,6 @@ void AISUpdate::doUpdate() LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << LL_ENDL; if (cat->getVersion() != version) { - LL_WARNS() << "Possible version mismatch for category " << cat->getName() - << ", viewer version " << cat->getVersion() - << " AIS version " << version << " !!!Adjusting local version!!!" << LL_ENDL; - // the AIS version should be considered the true version. Adjust // our local category model to reflect this version number. Otherwise // it becomes possible to get stuck with the viewer being out of @@ -1819,13 +1815,23 @@ void AISUpdate::doUpdate() // is performed. This occasionally gets out of sync however. if (version != LLViewerInventoryCategory::VERSION_UNKNOWN) { + LL_WARNS() << "Possible version mismatch for category " << cat->getName() + << ", viewer version " << cat->getVersion() + << " AIS version " << version << " !!!Adjusting local version!!!" << LL_ENDL; cat->setVersion(version); } else { // We do not account for update if version is UNKNOWN, so we shouldn't rise version // either or viewer will get stuck on descendants count -1, try to refetch folder instead - cat->fetch(); + // + // Todo: proper backoff? + + LL_WARNS() << "Possible version mismatch for category " << cat->getName() + << ", viewer version " << cat->getVersion() + << " AIS version " << version << " !!!Rerequesting category!!!" << LL_ENDL; + const S32 LONG_EXPIRY = 360; + cat->fetch(LONG_EXPIRY); } } } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index f4f403ab00..d0edaabc66 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -27,7 +27,6 @@ #include "llviewerprecompiledheaders.h" #include -#include #include "llaccordionctrltab.h" #include "llagent.h" #include "llagentcamera.h" @@ -1709,7 +1708,7 @@ void LLAppearanceMgr::removeOutfitPhoto(const LLUUID& outfit_id) sub_cat_array, outfit_item_array, LLInventoryModel::EXCLUDE_TRASH); - BOOST_FOREACH(LLViewerInventoryItem* outfit_item, outfit_item_array) + for (LLViewerInventoryItem* outfit_item : outfit_item_array) { LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem(); if (linked_item != NULL) @@ -3848,7 +3847,7 @@ void update_base_outfit_after_ordering() sub_cat_array, outfit_item_array, LLInventoryModel::EXCLUDE_TRASH); - BOOST_FOREACH(LLViewerInventoryItem* outfit_item, outfit_item_array) + for (LLViewerInventoryItem* outfit_item : outfit_item_array) { LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem(); if (linked_item != NULL) @@ -4165,7 +4164,7 @@ LLSD LLAppearanceMgr::dumpCOF() const LLUUID linked_asset_id(linked_item->getAssetUUID()); md5.update((unsigned char*)linked_asset_id.mData, 16); U32 flags = linked_item->getFlags(); - md5.update(boost::lexical_cast(flags)); + md5.update(std::to_string(flags)); } else if (LLAssetType::AT_LINK_FOLDER != inv_item->getActualType()) { diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a4e546c16f..bdd30dca94 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -158,7 +158,6 @@ // Third party library includes #include -#include #include #include #include @@ -1393,7 +1392,7 @@ bool LLAppViewer::init() // LLSD item(LeapCommand); // LeapCommand.append(item); // } -// BOOST_FOREACH(const std::string& leap, llsd::inArray(LeapCommand)) +// for (const auto& leap : llsd::inArray(LeapCommand)) // { // LL_INFOS("InitInfo") << "processing --leap \"" << leap << '"' << LL_ENDL; // // We don't have any better description of this plugin than the @@ -1973,7 +1972,7 @@ bool LLAppViewer::cleanup() LLNotifications::instance().clear(); // workaround for DEV-35406 crash on shutdown - LLEventPumps::instance().reset(); + LLEventPumps::instance().reset(true); GrowlManager::destroyManager(); // Growl support @@ -2759,7 +2758,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, LL_ERRS() << "Invalid settings location list" << LL_ENDL; } - BOOST_FOREACH(const SettingsGroup& group, mSettingsLocationList->groups) + for (const SettingsGroup& group : mSettingsLocationList->groups) { // skip settings groups that aren't the one we requested if (group.name() != location_key) continue; @@ -2771,7 +2770,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, return false; } - BOOST_FOREACH(const SettingsFile& file, group.files) + for (const SettingsFile& file : group.files) { // Skip quickprefs settings - we don't have a settings group // for it as it's not a regular settings file @@ -2844,11 +2843,11 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, std::string LLAppViewer::getSettingsFilename(const std::string& location_key, const std::string& file) { - BOOST_FOREACH(const SettingsGroup& group, mSettingsLocationList->groups) + for (const SettingsGroup& group : mSettingsLocationList->groups) { if (group.name() == location_key) { - BOOST_FOREACH(const SettingsFile& settings_file, group.files) + for (const SettingsFile& settings_file : group.files) { if (settings_file.name() == file) { @@ -3570,7 +3569,7 @@ void LLAppViewer::initStrings() // Now that we've set "[sourceid]", have to go back through // default_trans_args and reinitialize all those other keys because some // of them, in turn, reference "[sourceid]". - BOOST_FOREACH(std::string key, default_trans_args) + for (const std::string& key : default_trans_args) { std::string brackets(key), nobrackets(key); // Invalid to inspect key[0] if key is empty(). But then, the entire @@ -5541,17 +5540,24 @@ void LLAppViewer::idle() // When appropriate, update agent location to the simulator. F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); F32 agent_force_update_time = mLastAgentForceUpdate + agent_update_time; - BOOL force_update = gAgent.controlFlagsDirty() - || (mLastAgentControlFlags != gAgent.getControlFlags()) - || (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND)); - if (force_update || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND))) + bool timed_out = agent_update_time > (1.0f / (F32)AGENT_UPDATES_PER_SECOND); + BOOL force_send = + // if there is something to send + (gAgent.controlFlagsDirty() && timed_out) + // if something changed + || (mLastAgentControlFlags != gAgent.getControlFlags()) + // keep alive + || (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND)); + // timing out doesn't warranty that an update will be sent, + // just that it will be checked. + if (force_send || timed_out) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; // Send avatar and camera info mLastAgentControlFlags = gAgent.getControlFlags(); - mLastAgentForceUpdate = force_update ? 0 : agent_force_update_time; + mLastAgentForceUpdate = force_send ? 0 : agent_force_update_time; if(!gAgent.getPhantom()) - send_agent_update(force_update); + send_agent_update(force_send); agent_update_timer.reset(); } } diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 9d3ad0effc..d09a2d7d81 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -344,6 +344,11 @@ LLNotificationChiclet::LLNotificationChiclet(const Params& p) } } +LLNotificationChiclet::~LLNotificationChiclet() +{ + mNotificationChannel.reset(); +} + void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data) { std::string action = user_data.asString(); diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index 478e02a1ef..1f603d3f25 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -900,8 +900,9 @@ public: struct Params : public LLInitParam::Block{}; protected: - struct ChicletNotificationChannel : public LLNotificationChannel + class ChicletNotificationChannel : public LLNotificationChannel { + public: ChicletNotificationChannel(LLNotificationChiclet* chiclet) : LLNotificationChannel(LLNotificationChannel::Params().filter(filterNotification).name(chiclet->getSessionId().asString())) , mChiclet(chiclet) @@ -911,6 +912,7 @@ protected: connectToChannel("Offer"); connectToChannel("Notifications"); } + virtual ~ChicletNotificationChannel() {} static bool filterNotification(LLNotificationPtr notify); // connect counter updaters to the corresponding signals @@ -921,10 +923,11 @@ protected: LLNotificationChiclet* const mChiclet; }; - boost::scoped_ptr mNotificationChannel; - - LLNotificationChiclet(const Params& p); - + std::unique_ptr mNotificationChannel; + + LLNotificationChiclet(const Params& p); + ~LLNotificationChiclet(); + /** * Processes clicks on chiclet menu. */ diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index e03a7558e2..8445adecaa 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -79,7 +79,7 @@ namespace class ObjectInventoryFetcher: public LLVOInventoryListener { public: - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; ObjectInventoryFetcher(LLEventPump &pump, LLViewerObject* object, void* user_data) : mPump(pump), diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index c953efed72..6ac2edcf08 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -36,7 +36,6 @@ #include "fsfloaterim.h" // -#include #include "boost/lexical_cast.hpp" // Commenting out, let the user decide @@ -402,7 +401,7 @@ void LLConversationLog::deleteBackupLogs() std::vector backup_logs; getListOfBackupLogs(backup_logs); - BOOST_FOREACH(const std::string& fullpath, backup_logs) + for (const std::string& fullpath : backup_logs) { LLFile::remove(fullpath); } @@ -444,7 +443,7 @@ bool LLConversationLog::moveLog(const std::string &originDirectory, const std::s while(LLFile::isfile(backupFileName)) { ++backupFileCount; - backupFileName = targetDirectory + ".backup" + boost::lexical_cast(backupFileCount); + backupFileName = targetDirectory + ".backup" + std::to_string(backupFileCount); } //Rename the file to its backup name so it is not overwritten diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index b053094a5a..4334e34150 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -39,8 +39,6 @@ #include "llimview.h" //For LLIMModel #include "lltrans.h" -#include - // // Conversation items : common behaviors // @@ -302,8 +300,7 @@ void LLConversationItemSession::updateName(LLConversationItemParticipant* partic // In the case of a P2P conversation, we need to grab the name of the other participant in the session instance itself // as we do not create participants for such a session. - LLFolderViewModelItem * itemp; - BOOST_FOREACH(itemp, mChildren) + for (auto itemp : mChildren) { LLConversationItem* current_participant = dynamic_cast(itemp); // Add the avatar uuid to the list (except if it's the own agent uuid) diff --git a/indra/newview/llexternaleditor.cpp b/indra/newview/llexternaleditor.cpp index 422404774d..911bd9b0fd 100644 --- a/indra/newview/llexternaleditor.cpp +++ b/indra/newview/llexternaleditor.cpp @@ -32,7 +32,6 @@ #include "llprocess.h" #include "llsdutil.h" #include "llstring.h" -#include // static const std::string LLExternalEditor::sFilenameMarker = "%s"; @@ -111,7 +110,7 @@ LLExternalEditor::EErrorCode LLExternalEditor::run(const std::string& file_path) params.executable = mProcessParams.executable; // Substitute the filename marker in the command with the actual passed file name. - BOOST_FOREACH(const std::string& arg, mProcessParams.args) + for (const std::string& arg : mProcessParams.args) { std::string fixed(arg); LLStringUtil::replaceString(fixed, sFilenameMarker, file_path); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 4775686fc0..467c7e1d69 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1395,6 +1395,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLMaterial* mat = tep ? tep->getMaterialParams().get() : 0; // LLGLTFMaterial* gltf_mat = tep->getGLTFRenderMaterial(); + // show legacy when editing the fallback materials. + static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong"); + if( gltf_mat && getViewerObject()->isSelected() && showSelectedinBP ) + { + gltf_mat = nullptr; + } + // F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp index 5592320b4f..fae9b76d35 100644 --- a/indra/newview/llfloatercamera.cpp +++ b/indra/newview/llfloatercamera.cpp @@ -44,6 +44,7 @@ #include "llfirstuse.h" #include "llhints.h" #include "lltabcontainer.h" +#include "llviewercamera.h" #include "llvoavatarself.h" // [RLVa:KB] - @setcam #include "rlvactions.h" @@ -68,13 +69,19 @@ class LLPanelCameraZoom : public LLPanel { LOG_CLASS(LLPanelCameraZoom); + public: - LLPanelCameraZoom(); + struct Params : public LLInitParam::Block {}; + + LLPanelCameraZoom() { onCreate(); } /* virtual */ BOOL postBuild(); /* virtual */ void draw(); protected: + LLPanelCameraZoom(const Params& p) { onCreate(); } + + void onCreate(); void onZoomPlusHeldDown(); void onZoomMinusHeldDown(); void onSliderValueChanged(); @@ -83,9 +90,11 @@ protected: F32 getOrbitRate(F32 time); private: - LLButton* mPlusBtn; - LLButton* mMinusBtn; - LLSlider* mSlider; + LLButton* mPlusBtn { nullptr }; + LLButton* mMinusBtn{ nullptr }; + LLSlider* mSlider{ nullptr }; + + friend class LLUICtrlFactory; }; LLPanelCameraItem::Params::Params() @@ -161,10 +170,7 @@ static LLPanelInjector t_camera_zoom_panel("camera_zoom_panel // LLPanelCameraZoom //------------------------------------------------------------------------------- -LLPanelCameraZoom::LLPanelCameraZoom() -: mPlusBtn( NULL ), - mMinusBtn( NULL ), - mSlider( NULL ) +void LLPanelCameraZoom::onCreate() { mCommitCallbackRegistrar.add("Zoom.minus", boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this)); mCommitCallbackRegistrar.add("Zoom.plus", boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this)); @@ -175,9 +181,9 @@ LLPanelCameraZoom::LLPanelCameraZoom() BOOL LLPanelCameraZoom::postBuild() { - mPlusBtn = getChild ("zoom_plus_btn"); - mMinusBtn = getChild ("zoom_minus_btn"); - mSlider = getChild ("zoom_slider"); + mPlusBtn = getChild("zoom_plus_btn"); + mMinusBtn = getChild("zoom_minus_btn"); + mSlider = getChild("zoom_slider"); return LLPanel::postBuild(); } @@ -243,11 +249,80 @@ void activate_camera_tool() LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance()); }; +class LLCameraInfoPanel : public LLPanel +{ +public: + typedef std::function get_vector_t; + + LLCameraInfoPanel( + const LLView* parent, + const char* title, + const LLCoordFrame& camera, + const get_vector_t get_focus + ) + : LLPanel([&]() -> LLPanel::Params + { + LLPanel::Params params; + params.rect = LLRect(parent->getLocalRect()); + return params; + }()) + , mTitle(title) + , mCamera(camera) + , mGetFocus(get_focus) + , mFont(LLFontGL::getFontSansSerifBig()) + { + } + + virtual void draw() override + { + LLPanel::draw(); + + static const U32 HPADDING = 10; + static const U32 VPADDING = 5; + LLVector3 focus = mGetFocus(); + LLVector3 sight = focus - mCamera.mOrigin; + std::pair const data[] = + { + { "Origin:", mCamera.mOrigin }, + { "X Axis:", mCamera.mXAxis }, + { "Y Axis:", mCamera.mYAxis }, + { "Z Axis:", mCamera.mZAxis }, + { "Focus:", focus }, + { "Sight:", sight } + }; + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + S32 row_count = 1 + sizeof(data) / sizeof(*data); + S32 row_height = (height - VPADDING * 2) / row_count; + S32 top = height - VPADDING - row_height / 2; + mFont->renderUTF8(mTitle, 0, HPADDING, top, LLColor4::white, LLFontGL::LEFT, LLFontGL::VCENTER); + for (const auto& row : data) + { + top -= row_height; + mFont->renderUTF8(row.first, 0, HPADDING, top, LLColor4::white, LLFontGL::LEFT, LLFontGL::VCENTER); + const LLVector3& vector = row.second; + for (S32 i = 0; i < 3; ++i) + { + std::string text = llformat("%.6f", vector[i]); + S32 right = width / 4 * (i + 2) - HPADDING; + mFont->renderUTF8(text, 0, right, top, LLColor4::white, LLFontGL::RIGHT, LLFontGL::VCENTER); + } + } + } + +private: + const char* mTitle; + const LLCoordFrame& mCamera; + const get_vector_t mGetFocus; + const LLFontGL* mFont; +}; + // // Member functions // -/*static*/ bool LLFloaterCamera::inFreeCameraMode() +// static +bool LLFloaterCamera::inFreeCameraMode() { LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance(); @@ -272,6 +347,7 @@ void activate_camera_tool() return false; } +// static void LLFloaterCamera::resetCameraMode() { LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance(); @@ -291,6 +367,7 @@ void LLFloaterCamera::resetCameraMode() // } +// static void LLFloaterCamera::onAvatarEditingAppearance(bool editing) { sAppearanceEditing = editing; @@ -311,15 +388,46 @@ void LLFloaterCamera::onAvatarEditingAppearance(bool editing) // } +// static +void LLFloaterCamera::onDebugCameraToggled() +{ + if (LLFloaterCamera* instance = LLFloaterCamera::findInstance()) + { + instance->showDebugInfo(LLView::sDebugCamera); + } + + if (LLView::sDebugCamera) + { + LLFloaterReg::showInstanceOrBringToFront("camera"); + } +} + +void LLFloaterCamera::showDebugInfo(bool show) +{ + // Initially LLPanel contains 1 child "view_border" + if (show && mViewerCameraInfo->getChildCount() < 2) + { + mViewerCameraInfo->addChild(new LLCameraInfoPanel(mViewerCameraInfo, "Viewer Camera", *LLViewerCamera::getInstance(), + []() { return LLViewerCamera::getInstance()->getPointOfInterest(); })); + mAgentCameraInfo->addChild(new LLCameraInfoPanel(mAgentCameraInfo, "Agent Camera", gAgent.getFrameAgent(), + []() { return gAgent.getPosAgentFromGlobal(gAgentCamera.calcFocusPositionTargetGlobal()); })); + } + + mAgentCameraInfo->setVisible(show); + mViewerCameraInfo->setVisible(show); +} + void LLFloaterCamera::handleAvatarEditingAppearance(bool editing) { - } void LLFloaterCamera::update() { ECameraControlMode mode = determineMode(); - if (mode != mCurrMode) setMode(mode); + if (mode != mCurrMode) + { + setMode(mode); + } } @@ -328,7 +436,8 @@ void LLFloaterCamera::toPrevMode() switchMode(mPrevMode); } -/*static*/ void LLFloaterCamera::onLeavingMouseLook() +// static +void LLFloaterCamera::onLeavingMouseLook() { LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance(); if (floater_camera) @@ -402,12 +511,14 @@ void LLFloaterCamera::onOpen(const LLSD& key) // Optional small camera floater if (mPresetCombo) populatePresetCombo(); + + showDebugInfo(LLView::sDebugCamera); } void LLFloaterCamera::onClose(bool app_quitting) { //We don't care of camera mode if app is quitting - if(app_quitting) + if (app_quitting) return; // It is necessary to reset mCurrMode to CAMERA_CTRL_MODE_PAN so // to avoid seeing an empty floater when reopening the control. @@ -441,15 +552,19 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val) // virtual BOOL LLFloaterCamera::postBuild() { + mControls = getChild("controls"); + mAgentCameraInfo = getChild("agent_camera_info"); + mViewerCameraInfo = getChild("viewer_camera_info"); mRotate = getChild(ORBIT); - mZoom = findChild(ZOOM); + mZoom = getChild(ZOOM); mTrack = getChild(PAN); mPresetCombo = findChild("preset_combo"); // Optional small camera floater - // Improved camera floater - //getChild("precise_ctrs_label")->setShowCursorHand(false); - //getChild("precise_ctrs_label")->setSoundFlags(LLView::MOUSE_UP); - //getChild("precise_ctrs_label")->setClickedCallback(boost::bind(&LLFloaterReg::showInstance, "prefs_view_advanced", LLSD(), FALSE)); + //mPreciseCtrls = getChild("precise_ctrs_label"); + + //mPreciseCtrls->setShowCursorHand(false); + //mPreciseCtrls->setSoundFlags(LLView::MOUSE_UP); + //mPreciseCtrls->setClickedCallback(boost::bind(&LLFloaterReg::showInstance, "prefs_view_advanced", LLSD(), FALSE)); // // Phototools support @@ -615,6 +730,7 @@ void LLFloaterCamera::updateItemsSelection() getChild("object_view")->setValue(argument); } +// static void LLFloaterCamera::onClickCameraItem(const LLSD& param) { std::string name = param.asString(); @@ -704,7 +820,7 @@ void LLFloaterCamera::onClickCameraItem(const LLSD& param) } } -/*static*/ +// static void LLFloaterCamera::switchToPreset(const std::string& name) { // [RLVa:KB] - @setcam family diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h index f718e8248d..a8b3cb5775 100644 --- a/indra/newview/llfloatercamera.h +++ b/indra/newview/llfloatercamera.h @@ -64,6 +64,9 @@ public: /** Called when Avatar is entered/exited editing appearance mode */ static void onAvatarEditingAppearance(bool editing); + /** Called when opening and when "Advanced | Debug Camera" menu item is toggled */ + static void onDebugCameraToggled(); + /* determines actual mode and updates ui */ void update(); @@ -78,9 +81,9 @@ public: void populatePresetCombo(); - LLJoystickCameraRotate* mRotate; - LLPanelCameraZoom* mZoom; - LLJoystickCameraTrack* mTrack; + LLJoystickCameraRotate* mRotate { nullptr }; + LLPanelCameraZoom* mZoom { nullptr }; + LLJoystickCameraTrack* mTrack { nullptr }; private: @@ -122,6 +125,8 @@ private: void handleAvatarEditingAppearance(bool editing); + void showDebugInfo(bool show); + // Phototools support void switchViews(ECameraControlMode mode); @@ -134,7 +139,11 @@ private: ECameraControlMode mCurrMode; std::map mMode2Button; - LLComboBox* mPresetCombo; + LLPanel* mControls { nullptr }; + LLPanel* mViewerCameraInfo { nullptr }; + LLPanel* mAgentCameraInfo { nullptr }; + LLComboBox* mPresetCombo { nullptr }; + //LLTextBox* mPreciseCtrls { nullptr }; // Improved camera floater }; /** diff --git a/indra/newview/llfloatereditsky.cpp b/indra/newview/llfloatereditsky.cpp index cfd392c309..8bf4810026 100644 --- a/indra/newview/llfloatereditsky.cpp +++ b/indra/newview/llfloatereditsky.cpp @@ -84,7 +84,7 @@ BOOL LLFloaterEditSky::postBuild() mSkyPresetCombo = getChild("sky_preset_combo"); mMakeDefaultCheckBox = getChild("make_default_cb"); mSaveButton = getChild("save"); - mSkyAdapter = boost::make_shared(); + mSkyAdapter = std::make_shared(); LLEnvironment::instance().setSkyListChange(boost::bind(&LLFloaterEditSky::onSkyPresetListChange, this)); diff --git a/indra/newview/llfloatereditwater.cpp b/indra/newview/llfloatereditwater.cpp index e241366846..4c9c535a34 100644 --- a/indra/newview/llfloatereditwater.cpp +++ b/indra/newview/llfloatereditwater.cpp @@ -71,7 +71,7 @@ BOOL LLFloaterEditWater::postBuild() mMakeDefaultCheckBox = getChild("make_default_cb"); mSaveButton = getChild("save"); - mWaterAdapter = boost::make_shared(); + mWaterAdapter = std::make_shared(); LLEnvironment::instance().setWaterListChange(boost::bind(&LLFloaterEditWater::onWaterPresetListChange, this)); diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 9ac7c74746..6dbd5e5a6e 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -61,7 +61,6 @@ // [RLVa:KB] - @pay #include "rlvactions.h" // [/RLVa:KB] -#include "boost/foreach.hpp" const S32 EVENTS_PER_IDLE_LOOP_CURRENT_SESSION = 80; @@ -809,12 +808,11 @@ void LLFloaterIMContainer::setVisible(BOOL visible) void LLFloaterIMContainer::getDetachedConversationFloaters(floater_list_t& floaters) { - typedef conversations_widgets_map::value_type conv_pair; LLFloaterIMNearbyChat *nearby_chat = LLFloaterReg::findTypedInstance("nearby_chat"); - BOOST_FOREACH(conv_pair item, mConversationsWidgets) + for (const auto& [key, fvi] : mConversationsWidgets) { - LLConversationViewSession* widget = dynamic_cast(item.second); + LLConversationViewSession* widget = dynamic_cast(fvi); if (widget) { LLFloater* session_floater = widget->getSessionFloater(); diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index db54409bdc..24c42306b8 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -511,7 +511,7 @@ void LLFloaterIMNearbyChatScreenChannel::arrangeToasts() //----------------------------------------------------------------------------------------------- //LLFloaterIMNearbyChatHandler //----------------------------------------------------------------------------------------------- -boost::scoped_ptr LLFloaterIMNearbyChatHandler::sChatWatcher(new LLEventStream("LLChat")); +std::unique_ptr LLFloaterIMNearbyChatHandler::sChatWatcher(new LLEventStream("LLChat")); LLFloaterIMNearbyChatHandler::LLFloaterIMNearbyChatHandler() { diff --git a/indra/newview/llfloaterimnearbychathandler.h b/indra/newview/llfloaterimnearbychathandler.h index 0dc98ffc3c..1273494a6e 100644 --- a/indra/newview/llfloaterimnearbychathandler.h +++ b/indra/newview/llfloaterimnearbychathandler.h @@ -51,7 +51,7 @@ public: protected: virtual void initChannel(); - static boost::scoped_ptr sChatWatcher; + static std::unique_ptr sChatWatcher; // Add notification callback for new chat new_chat_signal_t mNewChatSignal; diff --git a/indra/newview/llfloaterinventorythumbnailshelper.cpp b/indra/newview/llfloaterinventorythumbnailshelper.cpp new file mode 100644 index 0000000000..814f88e9b9 --- /dev/null +++ b/indra/newview/llfloaterinventorythumbnailshelper.cpp @@ -0,0 +1,543 @@ +/** + * @file llfloaterinventorythumbnailshelper.cpp + * @author Callum Prentice + * @brief LLFloaterInventoryThumbnailsHelper class implementation + * + * Usage instructions and some brief notes can be found in Confluence here: + * https://lindenlab.atlassian.net/wiki/spaces/~174746736/pages/2928672843/Inventory+Thumbnail+Helper+Tool + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 "llaisapi.h" +#include "llclipboard.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "lltexteditor.h" +#include "lluictrlfactory.h" +#include "lluuid.h" + +#include "llfloaterinventorythumbnailshelper.h" + +LLFloaterInventoryThumbnailsHelper::LLFloaterInventoryThumbnailsHelper(const LLSD& key) + : LLFloater("floater_inventory_thumbnails_helper") +{ +} + +LLFloaterInventoryThumbnailsHelper::~LLFloaterInventoryThumbnailsHelper() +{ +} + +BOOL LLFloaterInventoryThumbnailsHelper::postBuild() +{ + mInventoryThumbnailsList = getChild("inventory_thumbnails_list"); + mInventoryThumbnailsList->setAllowMultipleSelection(true); + + mOutputLog = getChild("output_log"); + mOutputLog->setMaxTextLength(0xffff * 0x10); + + mPasteItemsBtn = getChild("paste_items_btn"); + mPasteItemsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteItems, this)); + mPasteItemsBtn->setEnabled(true); + + mPasteTexturesBtn = getChild("paste_textures_btn"); + mPasteTexturesBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onPasteTextures, this)); + mPasteTexturesBtn->setEnabled(true); + + mWriteThumbnailsBtn = getChild("write_thumbnails_btn"); + mWriteThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onWriteThumbnails, this)); + mWriteThumbnailsBtn->setEnabled(false); + + mLogMissingThumbnailsBtn = getChild("log_missing_thumbnails_btn"); + mLogMissingThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onLogMissingThumbnails, this)); + mLogMissingThumbnailsBtn->setEnabled(false); + + mClearThumbnailsBtn = getChild("clear_thumbnails_btn"); + mClearThumbnailsBtn->setCommitCallback(boost::bind(&LLFloaterInventoryThumbnailsHelper::onClearThumbnails, this)); + mClearThumbnailsBtn->setEnabled(false); + + return true; +} + +// Records an entry in the pasted items - saves it to a map and writes it to the log +// window for later confirmation/validation - since it uses a map, duplicates (based on +// the name) are discarded +void LLFloaterInventoryThumbnailsHelper::recordInventoryItemEntry(LLViewerInventoryItem* item) +{ + const std::string name = item->getName(); + + std::map::iterator iter = mItemNamesItems.find(name); + if (iter == mItemNamesItems.end()) + { + mItemNamesItems.insert({name, item}); + + writeToLog( + STRINGIZE( + "ITEM " << mItemNamesItems.size() << "> " << + name << + std::endl + ), false); + } + else + { + // dupe - do not save + } +} + +// Called when the user has copied items from their inventory and selects the Paste Items button +// in the UI - iterates over items and folders and saves details of each one. +// The first use of this tool is for updating NUX items and as such, only looks for OBJECTS, +// CLOTHING and BODYPARTS - later versions of this tool should make that selection editable. +void LLFloaterInventoryThumbnailsHelper::onPasteItems() +{ + if (!LLClipboard::instance().hasContents()) + { + return; + } + + writeToLog( + STRINGIZE( + "\n==== Pasting items from inventory ====" << + std::endl + ), false); + + std::vector objects; + LLClipboard::instance().pasteFromClipboard(objects); + size_t count = objects.size(); + + for (size_t i = 0; i < count; i++) + { + const LLUUID& entry = objects.at(i); + + // Check for a folder + const LLInventoryCategory* cat = gInventory.getCategory(entry); + if (cat) + { + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLIsType is_object(LLAssetType::AT_OBJECT); + gInventory.collectDescendentsIf(cat->getUUID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_object); + + LLIsType is_bodypart(LLAssetType::AT_BODYPART); + gInventory.collectDescendentsIf(cat->getUUID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_bodypart); + + LLIsType is_clothing(LLAssetType::AT_CLOTHING); + gInventory.collectDescendentsIf(cat->getUUID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_clothing); + + for (size_t i = 0; i < item_array.size(); i++) + { + LLViewerInventoryItem* item = item_array.at(i); + recordInventoryItemEntry(item); + } + } + + // Check for an item + LLViewerInventoryItem* item = gInventory.getItem(entry); + if (item) + { + const LLAssetType::EType item_type = item->getType(); + if (item_type == LLAssetType::AT_OBJECT || item_type == LLAssetType::AT_BODYPART || item_type == LLAssetType::AT_CLOTHING) + { + recordInventoryItemEntry(item); + } + } + } + + // update the main list view based on what we found + updateDisplayList(); + + // update the buttons enabled state based on what we found/saved + updateButtonStates(); +} + +// Records a entry in the pasted textures - saves it to a map and writes it to the log +// window for later confirmation/validation - since it uses a map, duplicates (based on +// the name) are discarded +void LLFloaterInventoryThumbnailsHelper::recordTextureItemEntry(LLViewerInventoryItem* item) +{ + const std::string name = item->getName(); + + std::map::iterator iter = mTextureNamesIDs.find(name); + if (iter == mTextureNamesIDs.end()) + { + LLUUID id = item->getAssetUUID(); + mTextureNamesIDs.insert({name, id}); + + writeToLog( + STRINGIZE( + "TEXTURE " << mTextureNamesIDs.size() << "> " << + name << + //" | " << + //id.asString() << + std::endl + ), false); + } + else + { + // dupe - do not save + } +} + +// Called when the user has copied textures from their inventory and selects the Paste Textures +// button in the UI - iterates over textures and folders and saves details of each one. +void LLFloaterInventoryThumbnailsHelper::onPasteTextures() +{ + if (!LLClipboard::instance().hasContents()) + { + return; + } + + writeToLog( + STRINGIZE( + "\n==== Pasting textures from inventory ====" << + std::endl + ), false); + + std::vector objects; + LLClipboard::instance().pasteFromClipboard(objects); + size_t count = objects.size(); + + for (size_t i = 0; i < count; i++) + { + const LLUUID& entry = objects.at(i); + + const LLInventoryCategory* cat = gInventory.getCategory(entry); + if (cat) + { + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLIsType is_object(LLAssetType::AT_TEXTURE); + gInventory.collectDescendentsIf(cat->getUUID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_object); + + for (size_t i = 0; i < item_array.size(); i++) + { + LLViewerInventoryItem* item = item_array.at(i); + recordTextureItemEntry(item); + } + } + + LLViewerInventoryItem* item = gInventory.getItem(entry); + if (item) + { + const LLAssetType::EType item_type = item->getType(); + if (item_type == LLAssetType::AT_TEXTURE) + { + recordTextureItemEntry(item); + } + } + } + + // update the main list view based on what we found + updateDisplayList(); + + // update the buttons enabled state based on what we found/saved + updateButtonStates(); +} + +// Updates the main list of entries in the UI based on what is in the maps/storage +void LLFloaterInventoryThumbnailsHelper::updateDisplayList() +{ + mInventoryThumbnailsList->deleteAllItems(); + + std::map::iterator item_iter = mItemNamesItems.begin(); + while (item_iter != mItemNamesItems.end()) + { + std::string item_name = (*item_iter).first; + + std::string existing_texture_name = std::string(); + LLUUID existing_thumbnail_id = (*item_iter).second->getThumbnailUUID(); + if (existing_thumbnail_id != LLUUID::null) + { + existing_texture_name = existing_thumbnail_id.asString(); + } + else + { + existing_texture_name = "none"; + } + + std::string new_texture_name = std::string(); + std::map::iterator texture_iter = mTextureNamesIDs.find(item_name); + if (texture_iter != mTextureNamesIDs.end()) + { + new_texture_name = (*texture_iter).first; + } + else + { + new_texture_name = "missing"; + } + + LLSD row; + row["columns"][EListColumnNum::NAME]["column"] = "item_name"; + row["columns"][EListColumnNum::NAME]["type"] = "text"; + row["columns"][EListColumnNum::NAME]["value"] = item_name; + row["columns"][EListColumnNum::NAME]["font"]["name"] = "Monospace"; + + row["columns"][EListColumnNum::EXISTING_TEXTURE]["column"] = "existing_texture"; + row["columns"][EListColumnNum::EXISTING_TEXTURE]["type"] = "text"; + row["columns"][EListColumnNum::EXISTING_TEXTURE]["font"]["name"] = "Monospace"; + row["columns"][EListColumnNum::EXISTING_TEXTURE]["value"] = existing_texture_name; + + row["columns"][EListColumnNum::NEW_TEXTURE]["column"] = "new_texture"; + row["columns"][EListColumnNum::NEW_TEXTURE]["type"] = "text"; + row["columns"][EListColumnNum::NEW_TEXTURE]["font"]["name"] = "Monospace"; + row["columns"][EListColumnNum::NEW_TEXTURE]["value"] = new_texture_name; + + mInventoryThumbnailsList->addElement(row); + + ++item_iter; + } +} + +#if 1 +// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. +// temp code in transition +void inventoryThumbnailsHelperCb(LLPointer cb, LLUUID id) +{ + if (cb.notNull()) + { + cb->fire(id); + } +} +#endif + +// Makes calls to the AIS v3 API to record the local changes made to the thumbnails. +// If this is not called, the operations (e.g. set thumbnail or clear thumbnail) +// appear to work but do not push the changes back to the inventory (local cache view only) +bool writeInventoryThumbnailID(LLUUID item_id, LLUUID thumbnail_asset_id) +{ + if (AISAPI::isAvailable()) + { + + LLSD updates; + updates["thumbnail"] = LLSD().with("asset_id", thumbnail_asset_id.asString()); + + LLPointer cb; + + AISAPI::completion_t cr = boost::bind(&inventoryThumbnailsHelperCb, cb, _1); + AISAPI::UpdateItem(item_id, updates, cr); + + return true; + } + else + { + LL_WARNS() << "Unable to write inventory thumbnail because the AIS API is not available" << LL_ENDL; + return false; + } +} + +// Called when the Write Thumbanils button is pushed. Iterates over the name/item and +// name/.texture maps and where it finds a common name, extracts what is needed and +// writes the thumbnail accordingly. +void LLFloaterInventoryThumbnailsHelper::onWriteThumbnails() +{ + // create and show confirmation (Yes/No) textbox since this is a destructive operation + LLNotificationsUtil::add("WriteInventoryThumbnailsWarning", LLSD(), LLSD(), + [&](const LLSD & notif, const LLSD & resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + std::map::iterator item_iter = mItemNamesItems.begin(); + while (item_iter != mItemNamesItems.end()) + { + std::string item_name = (*item_iter).first; + + std::map::iterator texture_iter = mTextureNamesIDs.find(item_name); + if (texture_iter != mTextureNamesIDs.end()) + { + LLUUID item_id = (*item_iter).second->getUUID(); + + LLUUID thumbnail_asset_id = (*texture_iter).second; + + writeToLog( + STRINGIZE( + "WRITING THUMB " << + (*item_iter).first << + "\n" << + "item ID: " << + item_id << + "\n" << + "thumbnail texture ID: " << + thumbnail_asset_id << + "\n" + ), true); + + + (*item_iter).second->setThumbnailUUID(thumbnail_asset_id); + + // This additional step (notifying AIS API) is required + // to make the changes persist outside of the local cache + writeInventoryThumbnailID(item_id, thumbnail_asset_id); + } + + ++item_iter; + } + + updateDisplayList(); + } + else + { + LL_INFOS() << "Writing new thumbnails was canceled" << LL_ENDL; + } + }); +} + +// Called when the Log Items with Missing Thumbnails is selected. This merely writes +// a list of all the items for which the thumbnail ID is Null. Typical use case is to +// copy from the log window, pasted to Slack to illustrate which items are missing +// a thumbnail +void LLFloaterInventoryThumbnailsHelper::onLogMissingThumbnails() +{ + std::map::iterator item_iter = mItemNamesItems.begin(); + while (item_iter != mItemNamesItems.end()) + { + LLUUID thumbnail_id = (*item_iter).second->getThumbnailUUID(); + + if (thumbnail_id == LLUUID::null) + { + writeToLog( + STRINGIZE( + "Missing thumbnail: " << + (*item_iter).first << + std::endl + ), true); + } + + ++item_iter; + } +} + +// Called when the Clear Thumbnail button is selected. Code to perform the clear (really +// just writing a NULL UUID into the thumbnail field) is behind an "Are you Sure?" dialog +// since it cannot be undone and potentinally, you could remove the thumbnails from your +// whole inventory this way. +void LLFloaterInventoryThumbnailsHelper::onClearThumbnails() +{ + // create and show confirmation (Yes/No) textbox since this is a destructive operation + LLNotificationsUtil::add("ClearInventoryThumbnailsWarning", LLSD(), LLSD(), + [&](const LLSD & notif, const LLSD & resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + std::map::iterator item_iter = mItemNamesItems.begin(); + while (item_iter != mItemNamesItems.end()) + { + (*item_iter).second->setThumbnailUUID(LLUUID::null); + + // This additional step (notifying AIS API) is required + // to make the changes persist outside of the local cache + const LLUUID item_id = (*item_iter).second->getUUID(); + writeInventoryThumbnailID(item_id, LLUUID::null); + + ++item_iter; + } + + updateDisplayList(); + } + else + { + LL_INFOS() << "Clearing on thumbnails was canceled" << LL_ENDL; + } + }); +} + +// Update the endabled state of some of the UI buttons based on what has +// been recorded so far. For example, if there are no valid item/texture pairs, +// then the Write Thumbnails button is not enabled. +void LLFloaterInventoryThumbnailsHelper::updateButtonStates() +{ + size_t found_count = 0; + + std::map::iterator item_iter = mItemNamesItems.begin(); + while (item_iter != mItemNamesItems.end()) + { + std::string item_name = (*item_iter).first; + + std::map::iterator texture_iter = mTextureNamesIDs.find(item_name); + if (texture_iter != mTextureNamesIDs.end()) + { + found_count++; + } + + ++item_iter; + } + + // the "Write Thumbnails" button is only enabled when there is at least one + // item with a matching texture ready to be written to the thumbnail field + if (found_count > 0) + { + mWriteThumbnailsBtn->setEnabled(true); + } + else + { + mWriteThumbnailsBtn->setEnabled(false); + } + + // The "Log Missing Items" and "Clear Thumbnails" buttons are only enabled + // when there is at least 1 item that was pasted from inventory (doesn't need + // to have a matching texture for these operations) + if (mItemNamesItems.size() > 0) + { + mLogMissingThumbnailsBtn->setEnabled(true); + mClearThumbnailsBtn->setEnabled(true); + } + else + { + mLogMissingThumbnailsBtn->setEnabled(false); + mClearThumbnailsBtn->setEnabled(false); + } +} + +// Helper function for writing a line to the log window. Currently the only additional +// feature is that it scrolls to the bottom each time a line is written but it +// is envisaged that other common actions will be added here eventually - E.G. write eavh +// line to the Second Life log too for example. +void LLFloaterInventoryThumbnailsHelper::writeToLog(std::string logline, bool prepend_newline) +{ + mOutputLog->appendText(logline, prepend_newline); + + mOutputLog->setCursorAndScrollToEnd(); +} diff --git a/indra/newview/llfloaterinventorythumbnailshelper.h b/indra/newview/llfloaterinventorythumbnailshelper.h new file mode 100644 index 0000000000..b42a85d1a5 --- /dev/null +++ b/indra/newview/llfloaterinventorythumbnailshelper.h @@ -0,0 +1,82 @@ +/** + * @file llfloaterinventorythumbnailshelper.h + * @author Callum Prentice + * @brief Helper floater for bulk processing of inventory thumbnails tool + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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_LLFLOATERINVENTORYTHUMBNAILSHELPER_H +#define LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H + +#include "llfloater.h" +class LLTextEditor; +class LLScrollListCtrl; +class LLViewerInventoryItem; +class LLUUID; + +class LLFloaterInventoryThumbnailsHelper: + public LLFloater +{ + friend class LLFloaterReg; + private: + LLFloaterInventoryThumbnailsHelper(const LLSD& key); + BOOL postBuild() override; + ~LLFloaterInventoryThumbnailsHelper(); + + LLScrollListCtrl* mInventoryThumbnailsList; + + LLTextEditor* mOutputLog; + + LLUICtrl* mPasteItemsBtn; + void onPasteItems(); + + LLUICtrl* mPasteTexturesBtn; + void onPasteTextures(); + + LLUICtrl* mWriteThumbnailsBtn; + void onWriteThumbnails(); + + LLUICtrl* mLogMissingThumbnailsBtn; + void onLogMissingThumbnails(); + + LLUICtrl* mClearThumbnailsBtn; + void onClearThumbnails(); + + void recordInventoryItemEntry(LLViewerInventoryItem* item); + void recordTextureItemEntry(LLViewerInventoryItem* item); + void updateButtonStates(); + void updateDisplayList(); + void writeToLog(std::string logline, bool prepend_newline); + + std::map mItemNamesItems; + std::map mTextureNamesIDs; + + enum EListColumnNum + { + NAME = 0, + EXISTING_TEXTURE = 1, + NEW_TEXTURE = 2 + }; +}; + +#endif // LL_LLFLOATERINVENTORYTHUMBNAILSHELPER_H diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index be54cc5f3c..183e80f901 100644 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -184,7 +184,8 @@ void LLPanelMarketplaceListings::draw() // Get the audit button enabled only after the whole inventory is fetched if (!mAuditBtn->getEnabled()) { - mAuditBtn->setEnabled(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()); + LLInventoryModelBackgroundFetch* inst = LLInventoryModelBackgroundFetch::getInstance(); + mAuditBtn->setEnabled(inst->isEverythingFetched() && !inst->folderFetchActive()); } LLPanel::draw(); @@ -411,8 +412,14 @@ BOOL LLFloaterMarketplaceListings::postBuild() mCategoryAddedObserver = new LLMarketplaceListingsAddedObserver(this); gInventory.addObserver(mCategoryAddedObserver); - // Fetch aggressively so we can interact with listings right onOpen() - fetchContents(); + + // Fetch aggressively so we can interact with listings as soon as possible + if (!fetchContents()) + { + const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + LLInventoryModelBackgroundFetch::instance().start(marketplacelistings_id, true); + } + return TRUE; } @@ -441,17 +448,19 @@ void LLFloaterMarketplaceListings::onFocusReceived() updateView(); } -void LLFloaterMarketplaceListings::fetchContents() +bool LLFloaterMarketplaceListings::fetchContents() { - if (mRootFolderId.notNull() && + if (mRootFolderId.notNull() && (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_LOADING) && (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_DONE)) - { + { LLMarketplaceData::instance().setDataFetchedSignal(boost::bind(&LLFloaterMarketplaceListings::updateView, this)); LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_LOADING); - LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true); + LLInventoryModelBackgroundFetch::instance().start(mRootFolderId, true); LLMarketplaceData::instance().getSLMListings(); - } + return true; + } + return false; } void LLFloaterMarketplaceListings::setRootFolder() diff --git a/indra/newview/llfloatermarketplacelistings.h b/indra/newview/llfloatermarketplacelistings.h index 15a1d13743..3c24dcc016 100644 --- a/indra/newview/llfloatermarketplacelistings.h +++ b/indra/newview/llfloatermarketplacelistings.h @@ -118,8 +118,8 @@ public: protected: void setRootFolder(); void setPanels(); - void fetchContents(); - + bool fetchContents(); + void setStatusString(const std::string& statusString); void onClose(bool app_quitting); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 3006930c24..aafd77cb5e 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1616,7 +1616,6 @@ void LLFloaterPreference::onBtnCancel(const LLSD& userdata) if (userdata.asString() == "closeadvanced") { LLFloaterReg::hideInstance("prefs_graphics_advanced"); - updateMaxComplexity(); } else { diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index d765327925..ef5b19ba2d 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -94,6 +94,8 @@ #include "llvograss.h" #include "llvotree.h" +#include "fspanelface.h" // switchable edit texture/materials panel + // Globals LLFloaterTools *gFloaterTools = NULL; bool LLFloaterTools::sShowObjectCost = true; @@ -174,8 +176,14 @@ void* LLFloaterTools::createPanelVolume(void* data) void* LLFloaterTools::createPanelFace(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelFace = new LLPanelFace(); - return floater->mPanelFace; + + // switchable edit texture/materials panel + // we should not need this here at all, we are adding the texture/materials + // panel in postBuild() + // floater->mPanelFace = new LLPanelFace(); + // return floater->mPanelFace; + return floater->findChild("Texture"); + // } //static @@ -229,6 +237,27 @@ LLPCode toolData[]={ BOOL LLFloaterTools::postBuild() { + // switchable edit texture/materials panel + LLPanel* panel; + if (gSavedSettings.getBOOL("FSUseNewTexturePanel")) + { + mFSPanelFace = new FSPanelFace; + panel = mFSPanelFace; + } + else + { + mPanelFace = new LLPanelFace; + panel = mPanelFace; + } + + LLTabContainer::TabPanelParams params; + params.panel = panel; + params.insert_at = (LLTabContainer::eInsertionPoint) PANEL_FACE; + + mTab = getChild("Object Info Tabs"); + mTab->addTabPanel(params); + // + // Hide until tool selected setVisible(FALSE); @@ -367,7 +396,11 @@ void LLFloaterTools::changePrecision(S32 decimal_precision) else if (decimal_precision > 7) decimal_precision = 7; mPanelObject->changePrecision(decimal_precision); - mPanelFace->changePrecision(decimal_precision); + // switchable edit texture/materials panel + // mPanelFace->changePrecision(decimal_precision); + if (mPanelFace) mPanelFace->changePrecision(decimal_precision); + if (mFSPanelFace) mFSPanelFace->changePrecision(decimal_precision); + // } // Create the popupview with a dummy center. It will be moved into place @@ -431,6 +464,7 @@ LLFloaterTools::LLFloaterTools(const LLSD& key) mPanelVolume(NULL), mPanelContents(NULL), mPanelFace(NULL), + mFSPanelFace(nullptr), // switchable edit texture/materials panel mPanelLandInfo(NULL), mCostTextBorder(NULL), @@ -470,7 +504,6 @@ LLFloaterTools::LLFloaterTools(const LLSD& key) // mCommitCallbackRegistrar.add("BuildTool.CopyKeys", boost::bind(&LLFloaterTools::onClickBtnCopyKeys,this)); mCommitCallbackRegistrar.add("BuildTool.Expand", boost::bind(&LLFloaterTools::onClickExpand,this)); - mCommitCallbackRegistrar.add("BuildTool.Flip", boost::bind(&LLPanelFace::onCommitFlip, _1, _2)); // // FIRE-7802: Grass and tree selection in build tool @@ -744,8 +777,20 @@ void LLFloaterTools::refresh() mPanelPermissions->refresh(); mPanelObject->refresh(); mPanelVolume->refresh(); - mPanelFace->refresh(); - mPanelFace->refreshMedia(); + // switchable edit texture/materials panel + // mPanelFace->refresh(); + // mPanelFace->refreshMedia(); + if (mPanelFace) + { + mPanelFace->refresh(); + mPanelFace->refreshMedia(); + } + if (mFSPanelFace) + { + mFSPanelFace->refresh(); + mFSPanelFace->refreshMedia(); + } + // mPanelContents->refresh(); mPanelLandInfo->refresh(); @@ -1142,7 +1187,11 @@ void LLFloaterTools::onClose(bool app_quitting) LLViewerJoystick::getInstance()->moveAvatar(false); // destroy media source used to grab media title - mPanelFace->unloadMedia(); + // switchable edit texture/materials panel + // mPanelFace->unloadMedia(); + if (mPanelFace) mPanelFace->unloadMedia(); + if (mFSPanelFace) mFSPanelFace->unloadMedia(); + // // Different from handle_reset_view in that it doesn't actually // move the camera if EditCameraMovement is not set. @@ -1626,3 +1675,39 @@ void LLFloaterTools::onSelectTreeGrassCombo() } } // + +// switchable edit texture/materials panel +void LLFloaterTools::refreshPanelFace() +{ + if (mPanelFace) mPanelFace->refresh(); + if (mFSPanelFace) mFSPanelFace->refresh(); +} + +LLRender::eTexIndex LLFloaterTools::getTextureDropChannel() +{ + if (mPanelFace) return mPanelFace->getTextureDropChannel(); + if (mFSPanelFace) return mFSPanelFace->getTextureDropChannel(); + return LLRender::NUM_TEXTURE_CHANNELS; // invalid +} + +LLRender::eTexIndex LLFloaterTools::getTextureChannelToEdit() +{ + if (mPanelFace) return mPanelFace->getTextureChannelToEdit(); + if (mFSPanelFace) return mFSPanelFace->getTextureChannelToEdit(); + return LLRender::NUM_TEXTURE_CHANNELS; // invalid +} + +LLGLTFMaterial::TextureInfo LLFloaterTools::getPBRDropChannel() +{ + if (mPanelFace) return mPanelFace->getPBRDropChannel(); + if (mFSPanelFace) return mFSPanelFace->getPBRDropChannel(); + return LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; // invalid +} + +LLMaterialPtr LLFloaterTools::createDefaultMaterial(LLMaterialPtr old_mat) +{ + if (mPanelFace) return mPanelFace->createDefaultMaterial(old_mat); + if (mFSPanelFace) return mFSPanelFace->createDefaultMaterial(old_mat); + return nullptr; // invalid +} +// diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index eec968d815..2ea5daaf93 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -50,6 +50,14 @@ class LLParcelSelection; class LLObjectSelection; class LLLandImpactsObserver; +// switchable edit texture/materials panel +#include "llgltfmaterial.h" +#include "llmaterial.h" +#include "llrender.h" + +class FSPanelFace; +// + typedef LLSafeHandle LLObjectSelectionHandle; class LLFloaterTools @@ -107,7 +115,14 @@ public: static void setGridMode(S32 mode); - LLPanelFace* getPanelFace() { return mPanelFace; } + // switchable edit texture/materials panel + // LLPanelFace* getPanelFace() { return mPanelFace; } + LLRender::eTexIndex getTextureDropChannel(); + LLRender::eTexIndex getTextureChannelToEdit(); + LLGLTFMaterial::TextureInfo getPBRDropChannel(); + LLMaterialPtr createDefaultMaterial(LLMaterialPtr old_mat); + void refreshPanelFace(); + // void onClickBtnCopyKeys(); void onClickExpand(); @@ -193,7 +208,7 @@ public: LLPanelObject *mPanelObject; LLPanelVolume *mPanelVolume; LLPanelContents *mPanelContents; - LLPanelFace *mPanelFace; +// LLPanelFace *mPanelFace; // switchable edit texture/materials panel LLPanelLandInfo *mPanelLandInfo; LLViewBorder* mCostTextBorder; @@ -215,6 +230,9 @@ private: S32 mExpandedHeight; std::map mStatusText; + LLPanelFace* mPanelFace; // switchable edit texture/materials panel + FSPanelFace* mFSPanelFace; // switchable edit texture/materials panel + public: static bool sShowObjectCost; static bool sPreviousFocusOnAvatar; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index dd4176cba2..ac4c63c105 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -159,7 +159,7 @@ public: // typedef std::map,std::list > > DiffMap; // this version copies the lists etc., and thus is bad memory-wise typedef std::list StringList; - typedef boost::shared_ptr StringListPtr; + typedef std::shared_ptr StringListPtr; typedef std::map > DiffMap; DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 0ef63e2500..f2a395e9ce 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -376,6 +376,7 @@ void* LLFloaterWorldMap::createWorldMapView(void* data) BOOL LLFloaterWorldMap::postBuild() { mMapView = dynamic_cast(getChild("objects_mapview")); + mMapView->setPan(0, 0, true); LLComboBox *avatar_combo = getChild("friend combo"); avatar_combo->selectFirstItem(); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 0cb1639161..76ce15d3de 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3532,9 +3532,11 @@ void LLIMMgr::addMessage( // Fetch group chat history, enabled by default. if (gSavedPerAccountSettings.getBOOL("FetchGroupChatHistory")) { - std::string chat_url = gAgent.getRegion()->getCapability("ChatSessionRequest"); - LLCoros::instance().launch("chatterBoxHistoryCoro", - boost::bind(&chatterBoxHistoryCoro, chat_url, session_id, from, msg, timestamp)); + std::string chat_url = gAgent.getRegionCapability("ChatSessionRequest"); + if (!chat_url.empty()) + { + LLCoros::instance().launch("chatterBoxHistoryCoro", boost::bind(&chatterBoxHistoryCoro, chat_url, session_id, from, msg, timestamp)); + } } // Configurable IM sounds diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp index 3efbbd1003..454c32d6a9 100644 --- a/indra/newview/llinspecttexture.cpp +++ b/indra/newview/llinspecttexture.cpp @@ -84,7 +84,10 @@ LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p) } } } - + if ((!p.message.isProvided() || p.message().empty())) + { + return NULL; + } // No or more than one texture found => show default tooltip return LLUICtrlFactory::create(p); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 453d74ff38..ea230df94c 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2546,8 +2546,11 @@ BOOL LLFolderBridge::isItemMovable() const void LLFolderBridge::selectItem() { - // Have no fear: the first thing start() does is to test if everything for that folder has been fetched... - LLInventoryModelBackgroundFetch::instance().start(getUUID(), true); + LLViewerInventoryCategory* cat = gInventory.getCategory(getUUID()); + if (cat) + { + cat->fetch(); + } } void LLFolderBridge::buildDisplayName() const @@ -2898,8 +2901,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (is_agent_inventory) { const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - // FIRE-1392: Allow dragging all asset types into Landmarks folder - //const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); @@ -2907,8 +2909,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); const BOOL move_is_into_current_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_CURRENT_OUTFIT); - // FIRE-1392: Allow dragging all asset types into Landmarks folder - //const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); + const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); const BOOL move_is_into_lost_and_found = model->isObjectDescendentOf(mUUID, lost_and_found_id); //-------------------------------------------------------------------------------- @@ -3070,7 +3071,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size); } - if (is_movable) + if (is_movable && !move_is_into_landmarks) { LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); is_movable = active_panel != NULL; @@ -3296,7 +3297,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, return accept; } -void warn_move_inventory(LLViewerObject* object, boost::shared_ptr move_inv) +void warn_move_inventory(LLViewerObject* object, std::shared_ptr move_inv) { const char* dialog = NULL; if (object->flagScripted()) @@ -3309,7 +3310,7 @@ void warn_move_inventory(LLViewerObject* object, boost::shared_ptr mo } static LLNotificationPtr notification_ptr; - static boost::shared_ptr inv_ptr; + static std::shared_ptr inv_ptr; // Notification blocks user from interacting with inventories so everything that comes after first message // is part of this message - don'r show it again @@ -3422,7 +3423,7 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, if(drop && accept) { it = inventory_objects.begin(); - boost::shared_ptr move_inv(new LLMoveInv); + std::shared_ptr move_inv(new LLMoveInv); move_inv->mObjectID = object_id; move_inv->mCategoryID = category_id; move_inv->mCallback = callback; @@ -5718,7 +5719,7 @@ LLFontGL::StyleFlags LLMarketplaceFolderBridge::getLabelStyle() const // helper stuff -bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, boost::shared_ptr move_inv) +bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, std::shared_ptr move_inv) { LLFloaterOpenObject::LLCatAndWear* cat_and_wear = (LLFloaterOpenObject::LLCatAndWear* )move_inv->mUserData; LLViewerObject* object = gObjectList.findObject(move_inv->mObjectID); @@ -6246,7 +6247,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, if (accept && drop) { LLUUID item_id = inv_item->getUUID(); - boost::shared_ptr move_inv (new LLMoveInv()); + std::shared_ptr move_inv (new LLMoveInv()); move_inv->mObjectID = inv_item->getParentUUID(); two_uuids_t item_pair(mUUID, item_id); move_inv->mMoveList.push_back(item_pair); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index a22ac8a8d0..bb6cbedf73 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -883,7 +883,7 @@ struct LLMoveInv void* mUserData; }; -void warn_move_inventory(LLViewerObject* object, boost::shared_ptr move_inv); -bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, boost::shared_ptr); +void warn_move_inventory(LLViewerObject* object, std::shared_ptr move_inv); +bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, std::shared_ptr); #endif // LL_LLINVENTORYBRIDGE_H diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index e2b867a1b3..8bf5fd1a03 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -221,11 +221,17 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const && !LLInventoryModelBackgroundFetch::instance().inventoryFetchInProgress()) { LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id); - if ((!cat && folder_id.notNull()) || (cat && cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN)) + if ((!cat && folder_id.notNull())) + { + // Shouldn't happen? Server provides full list of folders on startup + LLInventoryModelBackgroundFetch::instance().start(folder_id, false); + } + else if (cat && cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) { // At the moment background fetch only cares about VERSION_UNKNOWN, - // so do not check isCategoryComplete that compares descendant count - LLInventoryModelBackgroundFetch::instance().start(folder_id, false); + // so do not check isCategoryComplete that compares descendant count, + // but if that is nesesary, do a forced scheduleFolderFetch. + cat->fetch(); } } diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 3e20321085..78f5cf9324 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -96,8 +96,6 @@ #include "rlvlocks.h" // [/RLVa:KB] -#include - // Firestorm includes #include "aoengine.h" #include "fsfloaterwearablefavorites.h" @@ -480,6 +478,13 @@ void copy_inventory_category(LLInventoryModel* model, gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID()); } +void copy_cb(const LLUUID& dest_folder, const LLUUID& root_id) +{ + // Decrement the count in root_id since that one item won't be copied over + LLMarketplaceData::instance().decrementValidationWaiting(root_id); + update_folder_cb(dest_folder); +}; + void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& root_copy_id, bool move_no_copy_items) { model->notifyObservers(); @@ -498,12 +503,21 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode LLMarketplaceData::instance().setValidationWaiting(root_id, count_descendants_items(cat->getUUID())); } + LLPointer cb; + if (root_copy_id.isNull()) + { + cb = new LLBoostFuncInventoryCallback(boost::bind(copy_cb, new_cat_uuid, root_id)); + } + else + { + cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); + } + // Copy all the items LLInventoryModel::item_array_t item_array_copy = *item_array; for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) { LLInventoryItem* item = *iter; - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); if (item->getIsLinkType()) { @@ -518,8 +532,11 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *)item; gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true); } - // Decrement the count in root_id since that one item won't be copied over - LLMarketplaceData::instance().decrementValidationWaiting(root_id); + if (root_copy_id.isNull()) + { + // Decrement the count in root_id since that one item won't be copied over + LLMarketplaceData::instance().decrementValidationWaiting(root_id); + } } else { @@ -3245,6 +3262,23 @@ bool get_selection_object_uuids(LLFolderView *root, uuid_vec_t& ids) void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root, const std::string& action, BOOL user_confirm) { std::set selected_items = root->getSelectionList(); + if (selected_items.empty() + && action != "wear" + && action != "wear_add" + && !isRemoveAction(action)) + { + // Was item removed while user was checking menu? + // "wear" and removal exlusions are due to use of + // getInventorySelectedUUIDs() below + LL_WARNS("Inventory") << "Menu tried to operate on empty selection" << LL_ENDL; + + if (("copy" == action) || ("cut" == action)) + { + LLClipboard::instance().reset(); + } + + return; + } // Prompt the user and check for authorization for some marketplace active listing edits if (user_confirm && (("delete" == action) || ("cut" == action) || ("rename" == action) || ("properties" == action) || ("task_properties" == action) || ("open" == action))) diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index abf797109d..6b25857068 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -2554,26 +2554,42 @@ void LLInventoryGallery::startDrag() { std::vector types; uuid_vec_t ids; + LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_AGENT; for (LLUUID& selected_id : mSelectedItemIDs) { const LLInventoryItem* item = gInventory.getItem(selected_id); if (item) { + if (item->getPermissions().getOwner() == ALEXANDRIA_LINDEN_ID) + { + src = LLToolDragAndDrop::SOURCE_LIBRARY; + } + EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(item->getType()); types.push_back(type); ids.push_back(selected_id); } const LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id); - if (cat && gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID()) - && !LLFolderType::lookupIsProtectedType((cat)->getPreferredType())) + if (cat) { - EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); - types.push_back(type); - ids.push_back(selected_id); + if (gInventory.isObjectDescendentOf(selected_id, gInventory.getLibraryRootFolderID())) + { + src = LLToolDragAndDrop::SOURCE_LIBRARY; + EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); + types.push_back(type); + ids.push_back(selected_id); + } + else if (gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID()) + && !LLFolderType::lookupIsProtectedType((cat)->getPreferredType())) + { + EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType()); + types.push_back(type); + ids.push_back(selected_id); + } } } - LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, LLToolDragAndDrop::SOURCE_AGENT); + LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, src); } bool LLInventoryGallery::areViewsInitialized() @@ -3475,7 +3491,7 @@ BOOL dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, BOOL drop, if (accept && drop) { - boost::shared_ptr move_inv (new LLMoveInv()); + std::shared_ptr move_inv (new LLMoveInv()); move_inv->mObjectID = inv_item->getParentUUID(); std::pair item_pair(folder_id, inv_item->getUUID()); move_inv->mMoveList.push_back(item_pair); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a290eb30c5..ccfe0a4196 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3842,6 +3842,9 @@ void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, vo gInventoryCallbacks.fire(callback_id, item_id); + // Message system at the moment doesn't support Thumbnails and potential + // newer features so just rerequest whole item + // // todo: instead of unpacking message fully, // grab only an item_id, then fetch LLInventoryModelBackgroundFetch::instance().scheduleItemFetch(item_id, true); @@ -4226,19 +4229,22 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) { - gInventory.updateCategory(*cit); - - // Temporary workaround: just fetch the item using AIS to get missing fields. - // If this works fine we might want to extract ids only from the message - // then use AIS as a primary fetcher - LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/); + gInventory.updateCategory(*cit); + if ((*cit)->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + // Temporary workaround: just fetch the item using AIS to get missing fields. + // If this works fine we might want to extract 'ids only' from the message + // then use AIS as a primary fetcher + LLInventoryModelBackgroundFetch::instance().scheduleFolderFetch((*cit)->getUUID(), true /*force, since it has changes*/); + } + // else already called fetch() above } for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) { gInventory.updateItem(*iit); // Temporary workaround: just fetch the item using AIS to get missing fields. - // If this works fine we might want to extract ids only from the message + // If this works fine we might want to extract 'ids only' from the message // then use AIS as a primary fetcher LLInventoryModelBackgroundFetch::instance().scheduleItemFetch((*iit)->getUUID(), true); } diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 382fdfc41d..6f8461d6ca 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -197,13 +197,16 @@ LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch(): mLastFetchCount(0), mFetchFolderCount(0), mAllRecursiveFoldersFetched(false), - mRecursiveInventoryFetchStarted(false), - mRecursiveLibraryFetchStarted(false), - mMinTimeBetweenFetches(0.3f) + mRecursiveInventoryFetchStarted(false), + mRecursiveLibraryFetchStarted(false), + mRecursiveMarketplaceFetchStarted(false), + mMinTimeBetweenFetches(0.3f) {} LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() -{} +{ + gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); +} bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const { @@ -318,6 +321,23 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } + else if (recursive && cat && cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_LISTINGS) + { + if (mFetchFolderQueue.empty() || mFetchFolderQueue.back().mUUID != id) + { + if (recursive && AISAPI::isAvailable()) + { + // Request marketplace folder and content separately + mFetchFolderQueue.push_front(FetchQueueInfo(id, FT_FOLDER_AND_CONTENT)); + } + else + { + mFetchFolderQueue.push_front(FetchQueueInfo(id, recursion_type)); + } + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + mRecursiveMarketplaceFetchStarted = true; + } + } else { if (AISAPI::isAvailable()) @@ -363,8 +383,22 @@ void LLInventoryModelBackgroundFetch::scheduleFolderFetch(const LLUUID& cat_id, mBackgroundFetchActive = true; mFolderFetchActive = true; - // Specific folder requests go to front of queue. - mFetchFolderQueue.push_front(FetchQueueInfo(cat_id, forced ? FT_FORCED : FT_DEFAULT)); + if (forced) + { + // check if already requested + if (mForceFetchSet.find(cat_id) == mForceFetchSet.end()) + { + mForceFetchSet.insert(cat_id); + mFetchItemQueue.push_front(FetchQueueInfo(cat_id, FT_FORCED)); + } + } + else + { + // Specific folder requests go to front of queue. + // version presence acts as dupplicate prevention for normal fetches + mFetchItemQueue.push_front(FetchQueueInfo(cat_id, FT_DEFAULT)); + } + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } @@ -374,8 +408,21 @@ void LLInventoryModelBackgroundFetch::scheduleItemFetch(const LLUUID& item_id, b if (mFetchItemQueue.empty() || mFetchItemQueue.front().mUUID != item_id) { mBackgroundFetchActive = true; + if (forced) + { + // check if already requested + if (mForceFetchSet.find(item_id) == mForceFetchSet.end()) + { + mForceFetchSet.insert(item_id); + mFetchItemQueue.push_front(FetchQueueInfo(item_id, FT_FORCED, false)); + } + } + else + { + // 'isFinished' being set acts as dupplicate prevention for normal fetches + mFetchItemQueue.push_front(FetchQueueInfo(item_id, FT_DEFAULT, false)); + } - mFetchItemQueue.push_front(FetchQueueInfo(item_id, forced ? FT_FORCED : FT_DEFAULT, false)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } } @@ -756,6 +803,7 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_i return; } + LLViewerInventoryCategory::EFetchType new_state = LLViewerInventoryCategory::FETCH_NONE; bool request_descendants = false; if (response_id.isNull()) // Failure { @@ -773,10 +821,12 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_i // set folder's version to prevent viewer from trying to request folder indefinetely LLViewerInventoryCategory* cat(gInventory.getCategory(request_id)); - if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + if (cat && cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) { cat->setVersion(0); } + // back off for a bit in case something tries to force-request immediately + new_state = LLViewerInventoryCategory::FETCH_FAILED; } } else @@ -829,7 +879,7 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID &request_i LLViewerInventoryCategory * cat(gInventory.getCategory(request_id)); if (cat) { - cat->setFetching(LLViewerInventoryCategory::FETCH_NONE); + cat->setFetching(new_state); } } @@ -918,7 +968,26 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis() if (isFolderFetchProcessingComplete() && mFolderFetchActive) { - setAllFoldersFetched(); + if (!mRecursiveInventoryFetchStarted || mRecursiveMarketplaceFetchStarted) + { + setAllFoldersFetched(); + } + else + { + // Intent is for marketplace request to happen after + // main inventory is done, unless requested by floater + mRecursiveMarketplaceFetchStarted = true; + const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + if (marketplacelistings_id.notNull()) + { + mFetchFolderQueue.push_front(FetchQueueInfo(marketplacelistings_id, FT_FOLDER_AND_CONTENT)); + } + else + { + setAllFoldersFetched(); + } + } + } if (isBulkFetchProcessingComplete()) @@ -978,22 +1047,8 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc if (child_cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_LISTINGS) { - // special case - content_done = false; - if (children.empty()) - { - // fetch marketplace alone - // Should it actually be fetched as FT_FOLDER_AND_CONTENT? - children.push_back(child_cat->getUUID()); - mExpectedFolderIds.push_back(child_cat->getUUID()); - child_cat->setFetching(target_state); - break; - } - else - { - // fetch marketplace alone next run - continue; - } + // special case, marketplace will fetch that as needed + continue; } children.push_back(child_cat->getUUID()); @@ -1067,10 +1122,10 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc mExpectedFolderIds.push_back(cat_id); EFetchType type = fetch_info.mFetchType; - LLUUID cat_id = cat->getUUID(); - AISAPI::completion_t cb = [cat_id , type](const LLUUID& response_id) + LLUUID cat_cb_id = cat_id; + AISAPI::completion_t cb = [cat_cb_id, type](const LLUUID& response_id) { - LLInventoryModelBackgroundFetch::instance().onAISFolderCalback(cat_id , response_id , type); + LLInventoryModelBackgroundFetch::instance().onAISFolderCalback(cat_cb_id, response_id , type); }; AISAPI::ITEM_TYPE item_type = AISAPI::INVENTORY; @@ -1129,6 +1184,11 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc AISAPI::FetchItem(fetch_info.mUUID, AISAPI::INVENTORY, ais_simple_item_callback); } } + + if (fetch_info.mFetchType == FT_FORCED) + { + mForceFetchSet.erase(fetch_info.mUUID); + } } // Bundle up a bunch of requests to send all at once. diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index 5af0e84e8c..038e6146e2 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -76,7 +76,6 @@ public: void incrFetchFolderCount(S32 fetching); bool isBulkFetchProcessingComplete() const; - bool isFolderFetchProcessingComplete() const; void setAllFoldersFetched(); typedef boost::function folders_fetched_callback_t; @@ -86,6 +85,7 @@ public: void addRequestAtBack(const LLUUID & id, bool recursive, bool is_category); protected: + bool isFolderFetchProcessingComplete() const; typedef enum { FT_DEFAULT = 0, @@ -122,6 +122,7 @@ protected: private: bool mRecursiveInventoryFetchStarted; bool mRecursiveLibraryFetchStarted; + bool mRecursiveMarketplaceFetchStarted; // AIS3 specific bool mAllRecursiveFoldersFetched; typedef boost::signals2::signal folders_fetched_signal_t; folders_fetched_signal_t mFoldersFetchedSignal; @@ -136,6 +137,7 @@ private: F32 mMinTimeBetweenFetches; fetch_queue_t mFetchFolderQueue; fetch_queue_t mFetchItemQueue; + uuid_set_t mForceFetchSet; std::list mExpectedFolderIds; // for debug, should this track time? // For legacy inventory BOOL mTimelyFetchPending; diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 0893c9c04e..97e92db86a 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -393,7 +393,6 @@ void LLInventoryFetchItemsObserver::startFetch() { // Start fetching whole folder since we need all items LLInventoryModelBackgroundFetch::getInstance()->scheduleFolderFetch(folder.first, true); - } else { diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 9b57b17227..c0a26d0995 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -45,7 +45,6 @@ #include #include #include -#include #if LL_MSVC #pragma warning(push) @@ -823,7 +822,7 @@ bool LLLogChat::moveTranscripts(const std::string originDirectory, std::string backupFileName; unsigned backupFileCount; - BOOST_FOREACH(const std::string& fullpath, listOfFilesToMove) + for (const std::string& fullpath : listOfFilesToMove) { backupFileCount = 0; newFullPath = targetDirectory + fullpath.substr(originDirectory.length(), std::string::npos); @@ -837,7 +836,7 @@ bool LLLogChat::moveTranscripts(const std::string originDirectory, while(LLFile::isfile(backupFileName)) { ++backupFileCount; - backupFileName = newFullPath + ".backup" + boost::lexical_cast(backupFileCount); + backupFileName = newFullPath + ".backup" + std::to_string(backupFileCount); } //Rename the file to its backup name so it is not overwritten @@ -894,7 +893,7 @@ void LLLogChat::deleteTranscripts() getListOfTranscriptFiles(list_of_transcriptions); getListOfTranscriptBackupFiles(list_of_transcriptions); - BOOST_FOREACH(const std::string& fullpath, list_of_transcriptions) + for (const std::string& fullpath : list_of_transcriptions) { S32 retry_count = 0; while (retry_count < 5) diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index 9466c1e083..ac8ec79076 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -93,7 +93,7 @@ private: void attemptComplete() { mAttemptComplete = true; } // In the future an event? - boost::scoped_ptr mLoginModule; + std::unique_ptr mLoginModule; LLNotificationsInterface* mNotifications; std::string mLoginState; diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 583742f970..1f4418f119 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -85,11 +85,11 @@ void LLWMIMethods::initCOMObjects() // Step 1: -------------------------------------------------- // Initialize COM. ------------------------------------------ - mHR = CoInitializeEx(0, COINIT_MULTITHREADED); + mHR = CoInitializeEx(0, COINIT_APARTMENTTHREADED); if (FAILED(mHR)) { + // if result S_FALSE, it's already initialized LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << std::hex << mHR << LL_ENDL; - return; } // Step 2: -------------------------------------------------- diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 18a3423ae9..972cf438b3 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -612,27 +612,17 @@ private: static void onIdleProcessQueue(void *userdata); // doesn't hold just marketplace related ids - static std::set sAddQueue; static std::set sStructureQueue; static bool sProcessingQueue; }; -std::set LLMarketplaceInventoryObserver::sAddQueue; std::set LLMarketplaceInventoryObserver::sStructureQueue; bool LLMarketplaceInventoryObserver::sProcessingQueue = false; void LLMarketplaceInventoryObserver::changed(U32 mask) { - if (mask & LLInventoryObserver::ADD && LLMarketplaceData::instance().hasValidationWaiting()) - { - // When things are added to the marketplace, we might need to re-validate and fix the containing listings - // just add whole list even if it contains items and non-marketplace folders - const std::set& changed_items = gInventory.getChangedIDs(); - sAddQueue.insert(changed_items.begin(), changed_items.end()); - } - - if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE)) - { + if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE)) + { // When things are changed in the inventory, this can trigger a host of changes in the marketplace listings folder: // * stock counts changing : no copy items coming in and out will change the stock count on folders // * version and listing folders : moving those might invalidate the marketplace data itself @@ -642,7 +632,7 @@ void LLMarketplaceInventoryObserver::changed(U32 mask) sStructureQueue.insert(changed_items.begin(), changed_items.end()); } - if (!sProcessingQueue && (!sAddQueue.empty() || !sStructureQueue.empty())) + if (!sProcessingQueue && !sStructureQueue.empty()) { gIdleCallbacks.addFunction(onIdleProcessQueue, NULL); // can do without sProcessingQueue, but it's usufull for simplicity and reliability @@ -656,40 +646,6 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata) const U64 MAX_PROCESSING_TIME = 1000; U64 stop_time = start_time + MAX_PROCESSING_TIME; - if (!sAddQueue.empty()) - { - // Make a copy of sAddQueue since decrementValidationWaiting - // can theoretically add more items - std::set add_queue(sAddQueue); - sAddQueue.clear(); - - std::set::const_iterator id_it = add_queue.begin(); - std::set::const_iterator id_end = add_queue.end(); - // First, count the number of items in this list... - S32 count = 0; - for (; id_it != id_end; ++id_it) - { - LLInventoryObject* obj = gInventory.getObject(*id_it); - if (obj && (LLAssetType::AT_CATEGORY != obj->getType())) - { - count++; - } - } - // Then, decrement the folders of that amount - // Note that of all of those, only one folder will be a listing folder (if at all). - // The other will be ignored by the decrement method. - id_it = add_queue.begin(); - for (; id_it != id_end; ++id_it) - { - LLInventoryObject* obj = gInventory.getObject(*id_it); - if (obj && (LLAssetType::AT_CATEGORY == obj->getType())) - { - // can trigger notifyObservers - LLMarketplaceData::instance().decrementValidationWaiting(obj->getUUID(), count); - } - } - } - while (!sStructureQueue.empty() && LLTimer::getTotalTime() < stop_time) { std::set::const_iterator id_it = sStructureQueue.begin(); @@ -723,7 +679,7 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata) sStructureQueue.erase(id_it); } - if (LLApp::isExiting() || (sAddQueue.empty() && sStructureQueue.empty())) + if (LLApp::isExiting() || sStructureQueue.empty()) { // Nothing to do anymore gIdleCallbacks.deleteFunction(onIdleProcessQueue, NULL); diff --git a/indra/newview/llmarketplacenotifications.cpp b/indra/newview/llmarketplacenotifications.cpp index 0886f9a990..02bd9e1f34 100644 --- a/indra/newview/llmarketplacenotifications.cpp +++ b/indra/newview/llmarketplacenotifications.cpp @@ -33,7 +33,6 @@ #include "llerror.h" -#include #include @@ -54,7 +53,7 @@ namespace LLMarketplaceInventoryNotifications llassert(!no_copy_payloads.empty()); llassert(no_copy_cb_action != NULL); - BOOST_FOREACH(const LLSD& payload, no_copy_payloads) + for (const LLSD& payload : no_copy_payloads) { (*no_copy_cb_action)(payload); } diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index 3b59b2f05e..577ab0048f 100644 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -68,7 +68,7 @@ class LLMaterialHttpHandler : public LLHttpSDHandler { public: typedef boost::function CallbackFunction; - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; LLMaterialHttpHandler(const std::string& method, CallbackFunction cback); diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 58f8bad3e4..8cd4793106 100644 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -116,10 +116,10 @@ protected: // Request (pure virtual base class for requests in the queue) class Request: - public boost::enable_shared_from_this + public std::enable_shared_from_this { public: - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; // Subclasses must implement this to build a payload for their request type. virtual LLSD getPayload() const = 0; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 6494d445fe..0c42b237fe 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -427,7 +427,7 @@ namespace { static S32 dump_num = 0; std::string make_dump_name(std::string prefix, S32 num) { - return prefix + boost::lexical_cast(num) + std::string(".xml"); + return prefix + std::to_string(num) + std::string(".xml"); } void dump_llsd_to_file(const LLSD& content, std::string filename); LLSD llsd_from_file(std::string filename); @@ -588,10 +588,10 @@ S32 LLMeshRepoThread::sRequestWaterLevel = 0; // LLMeshUploadThread class LLMeshHandlerBase : public LLCore::HttpHandler, - public boost::enable_shared_from_this + public std::enable_shared_from_this { public: - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; LOG_CLASS(LLMeshHandlerBase); LLMeshHandlerBase(U32 offset, U32 requested_bytes) diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 82be906194..3de312e13d 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -282,6 +282,16 @@ LLModelPreview::~LLModelPreview() mPreviewAvatar->markDead(); mPreviewAvatar = NULL; } + + mUploadData.clear(); + mTextureSet.clear(); + + for (U32 i = 0; i < LLModel::NUM_LODS; i++) + { + clearModel(i); + } + mBaseModel.clear(); + mBaseScene.clear(); } void LLModelPreview::updateDimentionsAndOffsets() diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 8cbd249073..7b077d967e 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -327,7 +327,7 @@ protected: vv_LLVolumeFace_t mBaseModelFacesCopy; U32 mGroup; - std::map, U32> mObject; + std::map, U32> mObject; // Improved LOD generation // Amount of triangles in original(base) model U32 mMaxTriangleLimit; diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp index b06131cf38..3f6a86106a 100644 --- a/indra/newview/llnotificationmanager.cpp +++ b/indra/newview/llnotificationmanager.cpp @@ -34,9 +34,6 @@ #include "llfloaterimnearbychathandler.h" #include "llnotifications.h" -#include -#include - using namespace LLNotificationsUI; //-------------------------------------------------------------------------- @@ -53,15 +50,15 @@ LLNotificationManager::~LLNotificationManager() //-------------------------------------------------------------------------- void LLNotificationManager::init() { - mChannels.push_back(new LLScriptHandler()); - mChannels.push_back(new LLTipHandler()); - mChannels.push_back(new LLGroupHandler()); - mChannels.push_back(new LLAlertHandler("Alerts", "alert", false)); - mChannels.push_back(new LLAlertHandler("AlertModal", "alertmodal", true)); - mChannels.push_back(new LLOfferHandler()); - mChannels.push_back(new LLHintHandler()); - mChannels.push_back(new LLBrowserNotification()); - mChannels.push_back(new LLIMHandler()); + mChannels.emplace_back(new LLScriptHandler()); + mChannels.emplace_back(new LLTipHandler()); + mChannels.emplace_back(new LLGroupHandler()); + mChannels.emplace_back(new LLAlertHandler("Alerts", "alert", false)); + mChannels.emplace_back(new LLAlertHandler("AlertModal", "alertmodal", true)); + mChannels.emplace_back(new LLOfferHandler()); + mChannels.emplace_back(new LLHintHandler()); + mChannels.emplace_back(new LLBrowserNotification()); + mChannels.emplace_back(new LLIMHandler()); mChatHandler = std::shared_ptr(new LLFloaterIMNearbyChatHandler()); } diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 65ec38a41d..efffcefc4a 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -28,8 +28,6 @@ #include "llviewerprecompiledheaders.h" // must be first include #include "lloutfitgallery.h" -#include - // llcommon #include "llcommonutils.h" #include "llfilesystem.h" @@ -1151,22 +1149,13 @@ LLContextMenu* LLOutfitGalleryContextMenu::createMenu() registrar.add("Outfit.Delete", boost::bind(LLOutfitGallery::onRemoveOutfit, selected_id)); registrar.add("Outfit.Create", boost::bind(&LLOutfitGalleryContextMenu::onCreate, this, _2)); registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitGalleryContextMenu::onThumbnail, this, selected_id)); + registrar.add("Outfit.Save", boost::bind(&LLOutfitGalleryContextMenu::onSave, this, selected_id)); enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitGalleryContextMenu::onEnable, this, _2)); enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitGalleryContextMenu::onVisible, this, _2)); return createFromFile("menu_gallery_outfit_tab.xml"); } -void LLOutfitGalleryContextMenu::onThumbnail(const LLUUID& outfit_cat_id) -{ - LLOutfitGallery* gallery = dynamic_cast(mOutfitList); - if (gallery && outfit_cat_id.notNull()) - { - LLSD data(outfit_cat_id); - LLFloaterReg::showInstance("change_item_thumbnail", data); - } -} - void LLOutfitGalleryContextMenu::onCreate(const LLSD& data) { LLWearableType::EType type = LLWearableType::getInstance()->typeNameToType(data.asString()); @@ -1201,7 +1190,6 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility() mMenu->setItemVisible("expand", FALSE); mMenu->setItemVisible("collapse", FALSE); mMenu->setItemVisible("thumbnail", have_selection); - mMenu->setItemVisible("sepatator3", TRUE); mMenu->setItemVisible("sort_folders_by_name", TRUE); LLOutfitListGearMenuBase::onUpdateItemsVisibility(); } @@ -1249,7 +1237,7 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id) sub_cat_array, outfit_item_array, LLInventoryModel::EXCLUDE_TRASH); - BOOST_FOREACH(LLViewerInventoryItem* outfit_item, outfit_item_array) + for (LLViewerInventoryItem* outfit_item : outfit_item_array) { LLViewerInventoryItem* linked_item = outfit_item->getLinkedItem(); LLUUID asset_id, inv_id; diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index f2366e6494..99371b1cec 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -193,17 +193,13 @@ public: friend class LLOutfitGallery; LLOutfitGalleryContextMenu(LLOutfitListBase* outfit_list) - : LLOutfitContextMenu(outfit_list), - mOutfitList(outfit_list){} + : LLOutfitContextMenu(outfit_list){} protected: /* virtual */ LLContextMenu* createMenu(); bool onEnable(LLSD::String param); bool onVisible(LLSD::String param); - void onThumbnail(const LLUUID& outfit_cat_id); void onCreate(const LLSD& data); -private: - LLOutfitListBase* mOutfitList; }; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 250eed9658..4064a8e29d 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -37,6 +37,7 @@ #include "llappearancemgr.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" +#include "llinspecttexture.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llmenubutton.h" @@ -70,7 +71,7 @@ bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LL return (LLStringUtil::compareDict(name1, name2) < 0); } -struct outfit_accordion_tab_params : public LLInitParam::Block +struct outfit_accordion_tab_params : public LLInitParam::Block { Mandatory wearable_list; @@ -152,7 +153,8 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id) std::string name = cat->getName(); outfit_accordion_tab_params tab_params(get_accordion_tab_params()); - LLAccordionCtrlTab* tab = LLUICtrlFactory::create(tab_params); + tab_params.cat_id = cat_id; + LLOutfitAccordionCtrlTab *tab = LLUICtrlFactory::create(tab_params); if (!tab) return; LLWearableItemsList* wearable_list = LLUICtrlFactory::create(tab_params.wearable_list); wearable_list->setDoubleClickCallback(boost::bind(&LLOutfitsList::onDoubleClick, this, wearable_list)); // FIRE-22484: Double-click wear in outfits list @@ -1199,6 +1201,8 @@ LLContextMenu* LLOutfitContextMenu::createMenu() registrar.add("Outfit.Edit", boost::bind(editOutfit)); registrar.add("Outfit.Rename", boost::bind(renameOutfit, selected_id)); registrar.add("Outfit.Delete", boost::bind(&LLOutfitListBase::removeSelected, mOutfitList)); + registrar.add("Outfit.Thumbnail", boost::bind(&LLOutfitContextMenu::onThumbnail, this, selected_id)); + registrar.add("Outfit.Save", boost::bind(&LLOutfitContextMenu::onSave, this, selected_id)); enable_registrar.add("Outfit.OnEnable", boost::bind(&LLOutfitContextMenu::onEnable, this, _2)); enable_registrar.add("Outfit.OnVisible", boost::bind(&LLOutfitContextMenu::onVisible, this, _2)); @@ -1263,6 +1267,31 @@ void LLOutfitContextMenu::renameOutfit(const LLUUID& outfit_cat_id) LLAppearanceMgr::instance().renameOutfit(outfit_cat_id); } +void LLOutfitContextMenu::onThumbnail(const LLUUID &outfit_cat_id) +{ + if (outfit_cat_id.notNull()) + { + LLSD data(outfit_cat_id); + LLFloaterReg::showInstance("change_item_thumbnail", data); + } +} + +void LLOutfitContextMenu::onSave(const LLUUID &outfit_cat_id) +{ + if (outfit_cat_id.notNull()) + { + LLNotificationsUtil::add("ConfirmOverwriteOutfit", LLSD(), LLSD(), + [outfit_cat_id](const LLSD ¬if, const LLSD &resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + LLAppearanceMgr::getInstance()->onOutfitFolderCreated(outfit_cat_id, true); + } + }); + } +} + LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist) : mOutfitList(olist), mMenu(NULL) @@ -1281,6 +1310,7 @@ LLOutfitListGearMenuBase::LLOutfitListGearMenuBase(LLOutfitListBase* olist) registrar.add("Gear.Expand", boost::bind(&LLOutfitListBase::onExpandAllFolders, mOutfitList)); registrar.add("Gear.WearAdd", boost::bind(&LLOutfitListGearMenuBase::onAdd, this)); + registrar.add("Gear.Save", boost::bind(&LLOutfitListGearMenuBase::onSave, this)); registrar.add("Gear.Thumbnail", boost::bind(&LLOutfitListGearMenuBase::onThumbnail, this)); registrar.add("Gear.SortByName", boost::bind(&LLOutfitListGearMenuBase::onChangeSortOrder, this)); @@ -1306,8 +1336,7 @@ void LLOutfitListGearMenuBase::onUpdateItemsVisibility() if (!mMenu) return; bool have_selection = getSelectedOutfitID().notNull(); - mMenu->setItemVisible("sepatator1", have_selection); - mMenu->setItemVisible("sepatator2", have_selection); + mMenu->setItemVisible("wear_separator", have_selection); mMenu->arrangeAndClear(); // update menu height } @@ -1352,6 +1381,20 @@ void LLOutfitListGearMenuBase::onAdd() } } +void LLOutfitListGearMenuBase::onSave() +{ + const LLUUID &selected_id = getSelectedOutfitID(); + LLNotificationsUtil::add("ConfirmOverwriteOutfit", LLSD(), LLSD(), + [selected_id](const LLSD ¬if, const LLSD &resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + LLAppearanceMgr::getInstance()->onOutfitFolderCreated(selected_id, true); + } + }); +} + void LLOutfitListGearMenuBase::onTakeOff() { // Take off selected outfit. @@ -1405,15 +1448,6 @@ bool LLOutfitListGearMenuBase::onVisible(LLSD::String param) return false; } - // *TODO This condition leads to menu item behavior inconsistent with - // "Wear" button behavior and should be modified or removed. - bool is_worn = LLAppearanceMgr::instance().getBaseOutfitUUID() == selected_outfit_id; - - if ("wear" == param) - { - return !is_worn; - } - return true; } @@ -1441,10 +1475,42 @@ void LLOutfitListGearMenu::onUpdateItemsVisibility() if (!mMenu) return; mMenu->setItemVisible("expand", TRUE); mMenu->setItemVisible("collapse", TRUE); - mMenu->setItemVisible("thumbnail", FALSE); // Never visible? - mMenu->setItemVisible("sepatator3", FALSE); + mMenu->setItemVisible("thumbnail", getSelectedOutfitID().notNull()); mMenu->setItemVisible("sort_folders_by_name", FALSE); LLOutfitListGearMenuBase::onUpdateItemsVisibility(); } +BOOL LLOutfitAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) +{ + // Make thumbnail tooltip work properly + //if (y >= getLocalRect().getHeight() - getHeaderHeight()) + static LLCachedControl showInventoryThumbnailTooltips(gSavedSettings, "FSShowInventoryThumbnailTooltips"); + if (showInventoryThumbnailTooltips && y >= getLocalRect().getHeight() - getHeaderHeight() && gInventory.getCategory(mFolderID)->getThumbnailUUID().notNull()) + { + LLSD params; + params["inv_type"] = LLInventoryType::IT_CATEGORY; + params["thumbnail_id"] = gInventory.getCategory(mFolderID)->getThumbnailUUID(); + params["item_id"] = mFolderID; + + // Make thumbnail tooltip work properly + static LLCachedControl inventoryThumbnailTooltipsDelay(gSavedSettings, "FSInventoryThumbnailTooltipsDelay"); + static LLCachedControl tooltip_fast_delay(gSavedSettings, "ToolTipFastDelay"); + F32 tooltipDelay = LLToolTipMgr::instance().toolTipVisible() ? tooltip_fast_delay() : inventoryThumbnailTooltipsDelay(); + // + + LLToolTipMgr::instance().show(LLToolTip::Params() + // Make thumbnail tooltip work properly + //.message(getToolTip()) + .message(gInventory.getCategory(mFolderID)->getName()) + .sticky_rect(calcScreenRect()) + // Make thumbnail tooltip work properly + //.delay_time(LLView::getTooltipTimeout()) + .delay_time(tooltipDelay) + .create_callback(boost::bind(&LLInspectTextureUtil::createInventoryToolTip, _1)) + .create_params(params)); + return TRUE; + } + + return LLAccordionCtrlTab::handleToolTip(x, y, mask); +} // EOF diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index d17e50dd70..31ebbf324a 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -31,6 +31,7 @@ #include "llpanel.h" // newview +#include "llaccordionctrltab.h" #include "llinventorymodel.h" #include "lllistcontextmenu.h" #include "llpanelappearancetab.h" @@ -168,6 +169,9 @@ protected: static void renameOutfit(const LLUUID& outfit_cat_id); + void onThumbnail(const LLUUID &outfit_cat_id); + void onSave(const LLUUID &outfit_cat_id); + private: LLOutfitListBase* mOutfitList; }; @@ -199,6 +203,7 @@ private: void onAdd(); void onTakeOff(); void onRename(); + void onSave(); void onCreate(const LLSD& data); bool onEnable(LLSD::String param); bool onVisible(LLSD::String param); @@ -214,7 +219,27 @@ protected: /*virtual*/ void onUpdateItemsVisibility(); }; -/** +class LLOutfitAccordionCtrlTab : public LLAccordionCtrlTab +{ +public: + struct Params : public LLInitParam::Block + { + Optional cat_id; + Params() : cat_id("cat_id") {} + }; + + virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); + + protected: + LLOutfitAccordionCtrlTab(const LLOutfitAccordionCtrlTab::Params &p) + : LLAccordionCtrlTab(p), + mFolderID(p.cat_id) + {} + friend class LLUICtrlFactory; + + LLUUID mFolderID; +}; + /** * @class LLOutfitsList * * A list of agents's outfits from "My Outfits" inventory category diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp index 0fdb9a57f3..854a32621a 100644 --- a/indra/newview/llpanelexperiencelisteditor.cpp +++ b/indra/newview/llpanelexperiencelisteditor.cpp @@ -40,7 +40,6 @@ #include "lltextbox.h" #include "lltrans.h" #include "llsdutil.h" -#include static LLPanelInjector t_panel_experience_list_editor("panel_experience_list_editor"); @@ -96,7 +95,7 @@ void LLPanelExperienceListEditor::addExperienceIds( const uuid_vec_t& experience void LLPanelExperienceListEditor::setExperienceIds( const LLSD& experience_ids ) { mExperienceIds.clear(); - BOOST_FOREACH(LLSD uuid, llsd::inArray(experience_ids)) + for (LLSD uuid : llsd::inArray(experience_ids)) { // Using insert(range) doesn't work here because the conversion from // LLSD to LLUUID is ambiguous: have to specify asUUID() for each entry. diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 6143151fe8..b5f055b879 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -603,6 +603,8 @@ LLPanelFace::LLPanelFace() mTitleMediaText(NULL), mNeedMediaTitle(true) { + buildFromFile("panel_tools_texture.xml"); // switchable edit texture/materials + USE_TEXTURE = LLTrans::getString("use_texture"); // Extended copy & paste buttons //mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2)); diff --git a/indra/newview/llpanelgroupbulkban.cpp b/indra/newview/llpanelgroupbulkban.cpp index cf1f0bc32f..2b6bf1bcd6 100644 --- a/indra/newview/llpanelgroupbulkban.cpp +++ b/indra/newview/llpanelgroupbulkban.cpp @@ -49,8 +49,6 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" -#include - LLPanelGroupBulkBan::LLPanelGroupBulkBan(const LLUUID& group_id) : LLPanelGroupBulk(group_id) { // Pass on construction of this panel to the control factory. @@ -163,8 +161,8 @@ void LLPanelGroupBulkBan::submit() // remove already banned users and yourself from request. std::vector banned_avatar_names; std::vector out_of_limit_names; - bool banning_self = FALSE; - std::vector::iterator conflict = std::find(banned_agent_list.begin(), banned_agent_list.end(), gAgent.getID()); + bool banning_self{ false }; + std::vector::iterator conflict = std::find(banned_agent_list.begin(), banned_agent_list.end(), gAgentID); if (conflict != banned_agent_list.end()) { banned_agent_list.erase(conflict); @@ -172,18 +170,17 @@ void LLPanelGroupBulkBan::submit() } if (group_datap) { - BOOST_FOREACH(const LLGroupMgrGroupData::ban_list_t::value_type& group_ban_pair, group_datap->mBanList) + for (const auto& [group_ban_agent_id, group_ban_data] : group_datap->mBanList) { - const LLUUID& group_ban_agent_id = group_ban_pair.first; std::vector::iterator conflict = std::find(banned_agent_list.begin(), banned_agent_list.end(), group_ban_agent_id); if (conflict != banned_agent_list.end()) { LLAvatarName av_name; LLAvatarNameCache::get(group_ban_agent_id, &av_name); - banned_avatar_names.push_back(av_name); + banned_avatar_names.emplace_back(av_name); banned_agent_list.erase(conflict); - if (banned_agent_list.size() == 0) + if (banned_agent_list.empty()) { break; } diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 12b1c368ed..42867855c8 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -114,7 +114,7 @@ private: static void updateServerCombo(); private: - boost::scoped_ptr mListener; + std::unique_ptr mListener; void updateLoginButtons(); void populateUserList(LLPointer credential); diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index 457f52bae8..d3089e2ea4 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -68,6 +68,8 @@ public: void openApearanceTab(const std::string& tab_name); + bool isCOFPanelActive() const; + // Show avatar complexity in appearance floater void updateAvatarComplexity(U32 complexity, const std::map& item_complexity, const std::map& temp_item_complexity, U32 body_parts_complexity); @@ -87,7 +89,6 @@ private: protected: void initTabPanels(); void onTabChange(); - bool isCOFPanelActive() const; bool isOutfitsListPanelActive() const; bool isOutfitsGalleryPanelActive() const; diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp index 7961c2e1a6..43e006ebe5 100644 --- a/indra/newview/llpanelprofileclassifieds.cpp +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -686,6 +686,8 @@ BOOL LLPanelProfileClassified::postBuild() mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelProfileClassified::onTextureSelected, this)); mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelProfileClassified::onTexturePickerMouseEnter, this)); mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelProfileClassified::onTexturePickerMouseLeave, this)); + mSnapshotCtrl->setAllowLocalTexture(FALSE); + mSnapshotCtrl->setBakeTextureEnabled(FALSE); mEditIcon->setVisible(false); mMapButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onMapClick, this)); @@ -703,7 +705,7 @@ BOOL LLPanelProfileClassified::postBuild() mCategoryCombo->add(LLTrans::getString(iter->second)); } - mClassifiedNameEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onChange, this), NULL); + mClassifiedNameEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onTitleChange, this), NULL); mClassifiedDescEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); mCategoryCombo->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); mContentTypeCombo->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); @@ -991,6 +993,8 @@ void LLPanelProfileClassified::onCancelClick() } else { + updateTabLabel(mClassifiedNameText->getValue()); + // Reload data to undo changes to forms LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); } @@ -1011,7 +1015,7 @@ void LLPanelProfileClassified::onSaveClick() } if(isNew() || isNewWithErrors()) { - if(gStatusBar->getBalance() < getPriceForListing()) + if(gStatusBar->getBalance() < MINIMUM_PRICE_FOR_LISTING) { LLNotificationsUtil::add("ClassifiedInsufficientFunds"); return; @@ -1462,6 +1466,12 @@ void LLPanelProfileClassified::onChange() enableSave(isDirty()); } +void LLPanelProfileClassified::onTitleChange() +{ + updateTabLabel(getClassifiedName()); + onChange(); +} + void LLPanelProfileClassified::doSave() { //*TODO: Fix all of this @@ -1487,6 +1497,14 @@ void LLPanelProfileClassified::doSave() void LLPanelProfileClassified::onPublishFloaterPublishClicked() { + if (mPublishFloater->getPrice() < MINIMUM_PRICE_FOR_LISTING) + { + LLSD args; + args["MIN_PRICE"] = MINIMUM_PRICE_FOR_LISTING; + LLNotificationsUtil::add("MinClassifiedPrice", args); + return; + } + setPriceForListing(mPublishFloater->getPrice()); doSave(); diff --git a/indra/newview/llpanelprofileclassifieds.h b/indra/newview/llpanelprofileclassifieds.h index 56deb05b18..582e0f8fbf 100644 --- a/indra/newview/llpanelprofileclassifieds.h +++ b/indra/newview/llpanelprofileclassifieds.h @@ -264,6 +264,7 @@ protected: void onSetLocationClick(); void onChange(); + void onTitleChange(); void onPublishFloaterPublishClicked(); diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 53e2eba3b1..031b8130a4 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -264,6 +264,9 @@ void LLPanelProfilePicks::onClickNewBtn() select_tab(true). label(pick_panel->getPickName())); updateButtons(); + + // Keep set location button + pick_panel->addLocationChangedCallbacks(); } void LLPanelProfilePicks::onClickDelete() @@ -538,6 +541,8 @@ LLPanelProfilePick::LLPanelProfilePick() , mLocationChanged(false) , mNewPick(false) , mIsEditing(false) + , mRegionCallbackConnection() + , mParcelCallbackConnection() { } @@ -555,6 +560,15 @@ LLPanelProfilePick::~LLPanelProfilePick() { LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); } + + if (mRegionCallbackConnection.connected()) + { + mRegionCallbackConnection.disconnect(); + } + if (mParcelCallbackConnection.connected()) + { + mParcelCallbackConnection.disconnect(); + } } void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id) @@ -634,6 +648,8 @@ BOOL LLPanelProfilePick::postBuild() mSnapshotCtrl = getChild("pick_snapshot"); mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelProfilePick::onSnapshotChanged, this)); + mSnapshotCtrl->setAllowLocalTexture(FALSE); + mSnapshotCtrl->setBakeTextureEnabled(FALSE); childSetAction("teleport_btn", boost::bind(&LLPanelProfilePick::onClickTeleport, this)); childSetAction("show_on_map_btn", boost::bind(&LLPanelProfilePick::onClickMap, this)); @@ -723,6 +739,7 @@ void LLPanelProfilePick::setSnapshotId(const LLUUID& id) void LLPanelProfilePick::setPickName(const std::string& name) { mPickName->setValue(name); + mPickNameStr = name; } const std::string LLPanelProfilePick::getPickName() @@ -833,6 +850,20 @@ void LLPanelProfilePick::onClickSetLocation() void LLPanelProfilePick::onClickSave() { + if (mRegionCallbackConnection.connected()) + { + mRegionCallbackConnection.disconnect(); + } + if (mParcelCallbackConnection.connected()) + { + mParcelCallbackConnection.disconnect(); + } + // Keep set location button + if (mLocationChanged) + { + onClickSetLocation(); + } + // sendUpdate(); mLocationChanged = false; @@ -840,6 +871,7 @@ void LLPanelProfilePick::onClickSave() void LLPanelProfilePick::onClickCancel() { + updateTabLabel(mPickNameStr); LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(getAvatarId(), getPickId()); mLocationChanged = false; enableSaveButton(FALSE); @@ -879,6 +911,14 @@ void LLPanelProfilePick::processParcelInfo(const LLParcelData& parcel_data) } } +// Keep set location button +void LLPanelProfilePick::addLocationChangedCallbacks() +{ + mRegionCallbackConnection = gAgent.addRegionChangedCallback([this]() { onClickSetLocation(); }); + mParcelCallbackConnection = gAgent.addParcelChangedCallback([this]() { onClickSetLocation(); }); +} +// + void LLPanelProfilePick::sendUpdate() { LLPickData pick_data; diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h index e6368f54b8..6c0bb103db 100644 --- a/indra/newview/llpanelprofilepicks.h +++ b/indra/newview/llpanelprofilepicks.h @@ -145,7 +145,9 @@ public: void setParcelID(const LLUUID& parcel_id) override { mParcelId = parcel_id; } void setErrorStatus(S32 status, const std::string& reason) override {}; -protected: + void addLocationChangedCallbacks(); // Keep set location button + + protected: /** * Sends remote parcel info request to resolve parcel name from its ID. @@ -244,6 +246,10 @@ protected: LLUUID mParcelId; LLUUID mPickId; LLUUID mRequestedId; + std::string mPickNameStr; + + boost::signals2::connection mRegionCallbackConnection; + boost::signals2::connection mParcelCallbackConnection; bool mLocationChanged; bool mNewPick; diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index f7426e93b2..821b3127ea 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -1253,6 +1253,12 @@ void LLTeleportHistoryPanel::onGearMenuAction(const LLSD& userdata) LLLandmarkActions::getSLURLfromPosGlobal(globalPos, boost::bind(&LLTeleportHistoryPanel::gotSLURLCallback, _1)); } + else if ("remove" == command_name) + { + LLTeleportHistoryStorage::getInstance()->removeItem(index); + LLTeleportHistoryStorage::getInstance()->save(); + showTeleportHistory(); + } // FIRE-31025: Clear TP history doesn't work anymore else if ("clear_history" == command_name) { @@ -1313,7 +1319,8 @@ bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const if ("teleport" == command_name || "view" == command_name || "show_on_map" == command_name - || "copy_slurl" == command_name) + || "copy_slurl" == command_name + || "remove" == command_name) { if (!mLastSelectedFlatlList) { diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 17b8ec0683..664e240484 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -114,7 +114,7 @@ public: void handleTerrainLinksetsResult(const LLSD &pContent); void handleTerrainLinksetsError(); - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; protected: @@ -139,7 +139,7 @@ private: LLPathfindingObjectPtr mTerrainLinksetPtr; }; -typedef boost::shared_ptr LinksetsResponderPtr; +typedef std::shared_ptr LinksetsResponderPtr; //--------------------------------------------------------------------------- // LLPathfindingManager diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h index bb44f780c8..258d0fdef7 100644 --- a/indra/newview/llpathfindingmanager.h +++ b/indra/newview/llpathfindingmanager.h @@ -107,8 +107,8 @@ private: void navMeshStatusRequestCoro(std::string url, U64 regionHandle, bool isGetStatusOnly); void navAgentStateRequestCoro(std::string url); void navMeshRebakeCoro(std::string url, rebake_navmesh_callback_t rebakeNavMeshCallback); - void linksetObjectsCoro(std::string url, boost::shared_ptr linksetsResponsderPtr, LLSD putData) const; - void linksetTerrainCoro(std::string url, boost::shared_ptr linksetsResponsderPtr, LLSD putData) const; + void linksetObjectsCoro(std::string url, std::shared_ptr linksetsResponsderPtr, LLSD putData) const; + void linksetTerrainCoro(std::string url, std::shared_ptr linksetsResponsderPtr, LLSD putData) const; void charactersCoro(std::string url, request_id_t requestId, object_request_callback_t callback) const; //void handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly); diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h index 87f32b8d56..ddc886f01c 100644 --- a/indra/newview/llpathfindingnavmesh.h +++ b/indra/newview/llpathfindingnavmesh.h @@ -39,7 +39,7 @@ class LLPathfindingNavMesh; class LLUUID; -typedef boost::shared_ptr LLPathfindingNavMeshPtr; +typedef std::shared_ptr LLPathfindingNavMeshPtr; class LLPathfindingNavMesh { diff --git a/indra/newview/llpathfindingnavmeshzone.h b/indra/newview/llpathfindingnavmeshzone.h index baa1cc5979..b76f4421a6 100644 --- a/indra/newview/llpathfindingnavmeshzone.h +++ b/indra/newview/llpathfindingnavmeshzone.h @@ -114,7 +114,7 @@ private: LLPathfindingNavMesh::navmesh_slot_t mNavMeshSlot; }; - typedef boost::shared_ptr NavMeshLocationPtr; + typedef std::shared_ptr NavMeshLocationPtr; typedef std::vector NavMeshLocationPtrs; void handleNavMeshLocation(); diff --git a/indra/newview/llpathfindingobject.h b/indra/newview/llpathfindingobject.h index b8d3ca2364..0114cce3f1 100644 --- a/indra/newview/llpathfindingobject.h +++ b/indra/newview/llpathfindingobject.h @@ -41,7 +41,7 @@ class LLPathfindingObject; class LLSD; -typedef boost::shared_ptr LLPathfindingObjectPtr; +typedef std::shared_ptr LLPathfindingObjectPtr; class LLPathfindingObject { diff --git a/indra/newview/llpathfindingobjectlist.h b/indra/newview/llpathfindingobjectlist.h index 61580582d3..e2e0dce4da 100644 --- a/indra/newview/llpathfindingobjectlist.h +++ b/indra/newview/llpathfindingobjectlist.h @@ -36,7 +36,7 @@ class LLPathfindingObjectList; -typedef boost::shared_ptr LLPathfindingObjectListPtr; +typedef std::shared_ptr LLPathfindingObjectListPtr; typedef std::map LLPathfindingObjectMap; class LLPathfindingObjectList diff --git a/indra/newview/llperfstats.cpp b/indra/newview/llperfstats.cpp index ac4cc1670b..e5172cd840 100644 --- a/indra/newview/llperfstats.cpp +++ b/indra/newview/llperfstats.cpp @@ -79,7 +79,7 @@ namespace LLPerfStats { assert_main_thread(); // these following variables are proxies for pipeline statics we do not need a two way update (no llviewercontrol handler) - if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("IndirectMaxNonImpostors", nonImpostors); }; + if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("RenderAvatarMaxNonImpostors", nonImpostors); }; if( tuningFlag & ReflectionDetail ){ gSavedSettings.setS32("RenderReflectionDetail", reflectionDetail); }; if( tuningFlag & FarClip ){ gSavedSettings.setF32("RenderFarClip", farClip); }; if( tuningFlag & UserMinDrawDistance ){ gSavedSettings.setF32("AutoTuneRenderFarClipMin", userMinDrawDistance); }; @@ -390,7 +390,7 @@ namespace LLPerfStats auto count = countNearbyAvatars(std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance)); if( count != tunables.nonImpostors ) { - tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER ); + tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : 0 ); LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance) << "m of the camera" << LL_ENDL; } } diff --git a/indra/newview/llplacesinventorypanel.cpp b/indra/newview/llplacesinventorypanel.cpp index dcafa5dd6a..f70d5eba27 100644 --- a/indra/newview/llplacesinventorypanel.cpp +++ b/indra/newview/llplacesinventorypanel.cpp @@ -121,3 +121,13 @@ S32 LLPlacesInventoryPanel::notify(const LLSD& info) } return 0; } + +BOOL LLPlacesInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, + EAcceptance *accept, std::string &tooltip_msg) +{ + if (mAcceptsDragAndDrop) + { + return LLInventoryPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + return FALSE; +} diff --git a/indra/newview/llplacesinventorypanel.h b/indra/newview/llplacesinventorypanel.h index 3c27964ec5..81b623b045 100644 --- a/indra/newview/llplacesinventorypanel.h +++ b/indra/newview/llplacesinventorypanel.h @@ -47,11 +47,14 @@ public: LLPlacesInventoryPanel(const Params& p); ~LLPlacesInventoryPanel(); - LLFolderView * createFolderRoot(LLUUID root_id ); + LLFolderView * createFolderRoot(LLUUID root_id ) override; void saveFolderState(); void restoreFolderState(); - virtual S32 notify(const LLSD& info) ; + virtual S32 notify(const LLSD& info) override; + + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, + EAcceptance *accept, std::string &tooltip_msg) override; private: LLSaveFolderState* mSavedFolderState; diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 98456a9a52..a546ae2d1d 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -1151,7 +1151,7 @@ void LLPreviewTexture::adjustAspectRatio() { // No existing ratio found, create an element that will show image at original ratio populateRatioList(); // makes sure previous custom ratio is cleared - std::string ratio = boost::lexical_cast(num)+":" + boost::lexical_cast(denom); + std::string ratio = std::to_string(num)+":" + std::to_string(denom); mRatiosList.push_back(ratio); combo->add(ratio); combo->setCurrentByIndex(mRatiosList.size()- 1); diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index 8087614d34..87c1330f8d 100644 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -259,17 +259,21 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint ) // Make sure we're not taking the slider out of bounds // (this is where some simple UI limits are stored) - F32 new_percent = weightToSlider(new_weight); - if (mSlider->getMinValue() < new_percent - && new_percent < mSlider->getMaxValue()) + F32 new_percent = weightToPercent(new_weight); + LLSliderCtrl* slider = getChild("param slider"); + if (slider) { - // [Legacy Bake] - //mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); - mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); - mWearable->writeToAvatar(gAgentAvatarp); - gAgentAvatarp->updateVisualParams(); + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + // [Legacy Bake] + //mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); + mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); + mWearable->writeToAvatar(gAgentAvatarp); + gAgentAvatarp->updateVisualParams(); - mSlider->setValue( weightToSlider( new_weight ) ); + slider->setValue( weightToPercent( new_weight ) ); + } } } } @@ -290,15 +294,19 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata ) F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); // step a fraction in the negative directiona F32 new_weight = current_weight - (range / 10.f); - F32 new_percent = self->weightToSlider(new_weight); - if (self->mSlider->getMinValue() < new_percent - && new_percent < self->mSlider->getMaxValue()) + F32 new_percent = self->weightToPercent(new_weight); + LLSliderCtrl* slider = self->getChild("param slider"); + if (slider) { - // [Legacy Bake] - //self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); - self->mWearable->writeToAvatar(gAgentAvatarp); - self->mSlider->setValue( self->weightToSlider( new_weight ) ); + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + // [Legacy Bake] + //self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); + self->mWearable->writeToAvatar(gAgentAvatarp); + slider->setValue( self->weightToPercent( new_weight ) ); + } } } @@ -322,18 +330,35 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata ) F32 range = self->mHintMax->getVisualParamWeight() - self->mHintMin->getVisualParamWeight(); // step a fraction in the negative direction F32 new_weight = current_weight + (range / 10.f); - F32 new_percent = self->weightToSlider(new_weight); - if (self->mSlider->getMinValue() < new_percent - && new_percent < self->mSlider->getMaxValue()) + F32 new_percent = self->weightToPercent(new_weight); + LLSliderCtrl* slider = self->getChild("param slider"); + if (slider) { - // [Legacy Bake] - //self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); - self->mWearable->writeToAvatar(gAgentAvatarp); - self->mSlider->setValue( self->weightToSlider( new_weight ) ); + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + // [Legacy Bake] + //self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); + self->mWearable->writeToAvatar(gAgentAvatarp); + slider->setValue( self->weightToPercent( new_weight ) ); + } } } } LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); } + + +F32 LLScrollingPanelParam::weightToPercent( F32 weight ) +{ + LLViewerVisualParam* param = mParam; + return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; +} + +F32 LLScrollingPanelParam::percentToWeight( F32 percent ) +{ + LLViewerVisualParam* param = mParam; + return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); +} diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h index dc344486fc..c7a47d5c7a 100644 --- a/indra/newview/llscrollingpanelparam.h +++ b/indra/newview/llscrollingpanelparam.h @@ -61,6 +61,9 @@ public: void onHintMouseDown( LLVisualParamHint* hint ); void onHintHeldDown( LLVisualParamHint* hint ); + F32 weightToPercent( F32 weight ); + F32 percentToWeight( F32 percent ); + public: // Constants for LLPanelVisualParam const static F32 PARAM_STEP_TIME_THRESHOLD; diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index 3c066cb590..97ef946b56 100644 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -43,7 +43,6 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const LLPanel::Params& pan LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, LLJoint* jointp, BOOL use_hints) : LLScrollingPanel( panel_params ), mParam(param), - mSlider(nullptr), mAllowModify(allow_modify), mWearable(wearable) { @@ -51,15 +50,13 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const LLPanel::Params& pan buildFromFile( "panel_scrolling_param.xml"); else buildFromFile( "panel_scrolling_param_base.xml"); - - mSlider = getChild("param slider"); - mSlider->setMaxValue(100.f * (mParam->getMaxWeight() - mParam->getMinWeight())); - mSlider->setValue(weightToSlider(param->getWeight())); + + getChild("param slider")->setValue(weightToPercent(param->getWeight())); std::string display_name = LLTrans::getString(param->getDisplayName()); - mSlider->setLabelArg("[DESC]", display_name); - mSlider->setEnabled(mAllowModify); - mSlider->setCommitCallback(boost::bind(LLScrollingPanelParamBase::onSliderMoved, mSlider, this)); + getChild("param slider")->setLabelArg("[DESC]", display_name); + getChildView("param slider")->setEnabled(mAllowModify); + childSetCommitCallback("param slider", LLScrollingPanelParamBase::onSliderMoved, this); setVisible(FALSE); setBorderVisible( FALSE ); @@ -80,9 +77,9 @@ void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify) } F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); - mSlider->setValue(weightToSlider( current_weight ) ); + getChild("param slider")->setValue(weightToPercent( current_weight ) ); mAllowModify = allow_modify; - mSlider->setEnabled(mAllowModify); + getChildView("param slider")->setEnabled(mAllowModify); } // static @@ -93,7 +90,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata) LLViewerVisualParam* param = self->mParam; F32 current_weight = self->mWearable->getVisualParamWeight( param->getID() ); - F32 new_weight = self->sliderToWeight( (F32)slider->getValue().asReal() ); + F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); if (current_weight != new_weight ) { // [Legacy Bake] @@ -104,12 +101,14 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata) } } -F32 LLScrollingPanelParamBase::weightToSlider(F32 weight) +F32 LLScrollingPanelParamBase::weightToPercent( F32 weight ) { - return (weight - mParam->getMinWeight()) * 100.f; + LLViewerVisualParam* param = mParam; + return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; } -F32 LLScrollingPanelParamBase::sliderToWeight(F32 slider) +F32 LLScrollingPanelParamBase::percentToWeight( F32 percent ) { - return slider / 100.f + mParam->getMinWeight(); + LLViewerVisualParam* param = mParam; + return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); } diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h index e7f88a21bd..9538826251 100644 --- a/indra/newview/llscrollingpanelparambase.h +++ b/indra/newview/llscrollingpanelparambase.h @@ -36,7 +36,6 @@ class LLViewerVisualParam; class LLWearable; class LLVisualParamHint; class LLViewerVisualParam; -class LLSliderCtrl; class LLJoint; class LLScrollingPanelParamBase : public LLScrollingPanel @@ -50,13 +49,11 @@ public: static void onSliderMoved(LLUICtrl* ctrl, void* userdata); - F32 weightToSlider(F32 weight); - F32 sliderToWeight(F32 slider); + F32 weightToPercent( F32 weight ); + F32 percentToWeight( F32 percent ); public: LLViewerVisualParam* mParam; - LLSliderCtrl* mSlider; - protected: BOOL mAllowModify; LLWearable *mWearable; diff --git a/indra/newview/llsculptidsize.cpp b/indra/newview/llsculptidsize.cpp index 5d051d0ebf..bedee32213 100644 --- a/indra/newview/llsculptidsize.cpp +++ b/indra/newview/llsculptidsize.cpp @@ -66,7 +66,7 @@ void LLSculptIDSize::inc(const LLDrawable *pdrawable, int sz) if (itLU.first == itLU.second) { //register //llassert(mSizeInfo.get().end() == mSizeInfo.get().find(pdrawable)); - mSizeInfo.get().insert(Info(pdrawable, sz, boost::make_shared(sz), sculptId)); + mSizeInfo.get().insert(Info(pdrawable, sz, std::make_shared(sz), sculptId)); total_size = sz; } else diff --git a/indra/newview/llsculptidsize.h b/indra/newview/llsculptidsize.h index 87ee417b86..679fcbd44c 100644 --- a/indra/newview/llsculptidsize.h +++ b/indra/newview/llsculptidsize.h @@ -52,7 +52,7 @@ public: struct Info { - typedef boost::shared_ptr PtrSizeSum; + typedef std::shared_ptr PtrSizeSum; Info(const LLDrawable *drawable, int size, PtrSizeSum sizeInfo, LLUUID sculptId) : mDrawable(drawable) diff --git a/indra/newview/llsearchableui.h b/indra/newview/llsearchableui.h index 31f11eb8ef..84fcefb835 100644 --- a/indra/newview/llsearchableui.h +++ b/indra/newview/llsearchableui.h @@ -93,7 +93,7 @@ namespace ll { struct SearchableItem; - typedef boost::shared_ptr< SearchableItem > SearchableItemPtr; + typedef std::shared_ptr< SearchableItem > SearchableItemPtr; typedef std::vector< SearchableItemPtr > tSearchableItemList; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index a4bdf6950a..bc519ed7ef 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -97,7 +97,7 @@ #include "llvovolume.h" #include "pipeline.h" #include "llviewershadermgr.h" -#include "llpanelface.h" +// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "rlvactions.h" #include "rlvhandler.h" @@ -1919,8 +1919,52 @@ bool LLObjectSelection::applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* i //----------------------------------------------------------------------------- // selectionSetImage() //----------------------------------------------------------------------------- +// Allow editing of non-PBR materials in-situ +template +struct TextureApplyFunctor : public LLSelectedTEFunctor +{ + LLViewerInventoryItem* mItem; + LLUUID mImageID; + TextureApplyFunctor(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {} + bool apply(LLViewerObject* objectp, S32 te) override + { + if(!objectp || !objectp->permModify()) + { + return false; + } + + if (mItem && objectp->isAttachment()) + { + const LLPermissions& perm = mItem->getPermissions(); + BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; + if (!unrestricted) + { + return false; + } + } + + if (mItem) + { + if constexpr (IsPBR) + { + LLToolDragAndDrop::dropTextureOneFace(objectp, te, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, false); + } + else + { + LLToolDragAndDrop::dropTextureOneFace(objectp, te, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, false, -2); // -2 means no PBR + } + } + else // not an inventory item + { + objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + } + + return true; + } +}; +// // *TODO: re-arch texture applying out of lltooldraganddrop -bool LLSelectMgr::selectionSetImage(const LLUUID& imageid) +bool LLSelectMgr::selectionSetImage(const LLUUID& imageid, bool isPBR) { // First for (no copy) textures and multiple object selection LLViewerInventoryItem* item = gInventory.getItem(imageid); @@ -1935,60 +1979,73 @@ bool LLSelectMgr::selectionSetImage(const LLUUID& imageid) return false; } - struct f : public LLSelectedTEFunctor - { - LLViewerInventoryItem* mItem; - LLUUID mImageID; - f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {} - bool apply(LLViewerObject* objectp, S32 te) - { - if(!objectp || !objectp->permModify()) - { - return false; - } + // Allow editing of non-PBR materials in-situ + // struct f : public LLSelectedTEFunctor + // { + // LLViewerInventoryItem* mItem; + // LLUUID mImageID; + // f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {} + // bool apply(LLViewerObject* objectp, S32 te) + // { + // if(!objectp || !objectp->permModify()) + // { + // return false; + // } - // Might be better to run willObjectAcceptInventory - if (mItem && objectp->isAttachment()) - { - const LLPermissions& perm = mItem->getPermissions(); - BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; - if (!unrestricted) - { - // Attachments are in world and in inventory simultaneously, - // at the moment server doesn't support such a situation. - return false; - } - } + // // Might be better to run willObjectAcceptInventory + // if (mItem && objectp->isAttachment()) + // { + // const LLPermissions& perm = mItem->getPermissions(); + // BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; + // if (!unrestricted) + // { + // // Attachments are in world and in inventory simultaneously, + // // at the moment server doesn't support such a situation. + // return false; + // } + // } - if (mItem) - { - LLToolDragAndDrop::dropTextureOneFace(objectp, - te, - mItem, - LLToolDragAndDrop::SOURCE_AGENT, - LLUUID::null, - false); - } - else // not an inventory item - { - // Texture picker defaults aren't inventory items - // * Don't need to worry about permissions for them - // * Can just apply the texture and be done with it. - objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); - } - - return true; - } - }; + // if (mItem) + // { + // LLToolDragAndDrop::dropTextureOneFace(objectp, + // te, + // mItem, + // LLToolDragAndDrop::SOURCE_AGENT, + // LLUUID::null, + // false); + // } + // else // not an inventory item + // { + // // Texture picker defaults aren't inventory items + // // * Don't need to worry about permissions for them + // // * Can just apply the texture and be done with it. + // objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + // } + // return true; + // } + // }; + // if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) { getSelection()->applyNoCopyTextureToTEs(item); } else { - f setfunc(item, imageid); - getSelection()->applyToTEs(&setfunc); + // Allow editing of non-PBR materials in-situ + // f setfunc(item, imageid); + // getSelection()->applyToTEs(&setfunc); + TextureApplyFunctor setfuncPBR(item, imageid); // For PBR textures + TextureApplyFunctor setfuncBP(item, imageid); // For non-PBR textures + if(isPBR) + { + getSelection()->applyToTEs(&setfuncPBR); + } + else + { + getSelection()->applyToTEs(&setfuncBP); + } + // } @@ -2258,7 +2315,9 @@ void LLSelectMgr::selectionRevertShinyColors() LLMaterialPtr old_mat = object->getTEref(te).getMaterialParams(); if (!old_mat.isNull()) { - LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat); + // switchable edit texture/materials panel + // LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat); + LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat); new_mat->setSpecularLightColor(color); object->getTEref(te).setMaterialParams(new_mat); LLMaterialMgr::getInstance()->put(object->getID(), te, *new_mat); @@ -3174,7 +3233,9 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch) if (tep && !tep->getMaterialParams().isNull()) { LLMaterialPtr orig = tep->getMaterialParams(); - LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + // switchable edit texture/materials panel + // LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + LLMaterialPtr p = gFloaterTools->createDefaultMaterial(orig); p->setNormalRepeat(normal_scale_s, normal_scale_t); p->setSpecularRepeat(specular_scale_s, specular_scale_t); @@ -3200,7 +3261,9 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch) if (tep && !tep->getMaterialParams().isNull()) { LLMaterialPtr orig = tep->getMaterialParams(); - LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + // switchable edit texture/materials panel + // LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + LLMaterialPtr p = gFloaterTools->createDefaultMaterial(orig); p->setNormalRepeat(normal_scale_s, normal_scale_t); p->setSpecularRepeat(specular_scale_s, specular_scale_t); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 0902fc1b39..5bea652f10 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -717,7 +717,7 @@ public: void selectionSetDensity(F32 density); void selectionSetRestitution(F32 restitution); void selectionSetMaterial(U8 material); - bool selectionSetImage(const LLUUID& imageid); // could be item or asset id + bool selectionSetImage(const LLUUID& imageid, bool isPBR=true); // inject PBR awareness. bool selectionSetGLTFMaterial(const LLUUID& mat_id); // material id only void selectionSetColor(const LLColor4 &color); void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index c94a4f7875..e3a72a2a23 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -363,6 +363,15 @@ void LLSidepanelAppearance::toggleMyOutfitsPanel(BOOL visible, const std::string } } +bool LLSidepanelAppearance::isCOFPanelVisible() +{ + if (mPanelOutfitsInventory && mPanelOutfitsInventory->getVisible()) + { + return mPanelOutfitsInventory->isCOFPanelActive(); + } + return false; +} + void LLSidepanelAppearance::toggleOutfitEditPanel(BOOL visible, BOOL disable_camera_switch) { if (!mOutfitEdit || mOutfitEdit->getVisible() == visible) diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h index ed0ef60d47..c9913a4778 100644 --- a/indra/newview/llsidepanelappearance.h +++ b/indra/newview/llsidepanelappearance.h @@ -70,6 +70,8 @@ public: void updateToVisibility( const LLSD& new_visibility ); LLPanelEditWearable* getWearable(){ return mEditWearable; } + bool isCOFPanelVisible(); + // [RLVa:KB] - Checked: 2010-09-16 (RLVa-1.2.1a) | Added: RLVa-1.2.1a bool isOutfitEditPanelVisible() const; bool isWearableEditPanelVisible() const; diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index 0222ca2e03..04e2c9b8b8 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -46,8 +46,6 @@ #include "llviewercontrol.h" // HACK for destinations guide on startup #include "llinventorymodel.h" // HACK to disable starter avatars button for NUX -#include - #include "fscommon.h" #include "quickprefs.h" @@ -319,7 +317,7 @@ bool LLToolBarView::loadToolbars(bool force_default) mToolbars[LLToolBarEnums::TOOLBAR_LEFT]->setLayoutStyle(layout_style); } // - BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.left_toolbar.commands) + for (const LLCommandId::Params& command_params : toolbar_set.left_toolbar.commands) { if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_LEFT])) { @@ -347,7 +345,7 @@ bool LLToolBarView::loadToolbars(bool force_default) mToolbars[LLToolBarEnums::TOOLBAR_RIGHT]->setLayoutStyle(layout_style); } // - BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.right_toolbar.commands) + for (const LLCommandId::Params& command_params : toolbar_set.right_toolbar.commands) { if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_RIGHT])) { @@ -375,7 +373,7 @@ bool LLToolBarView::loadToolbars(bool force_default) mToolbars[LLToolBarEnums::TOOLBAR_BOTTOM]->setLayoutStyle(layout_style); } // - BOOST_FOREACH(const LLCommandId::Params& command_params, toolbar_set.bottom_toolbar.commands) + for (const LLCommandId::Params& command_params : toolbar_set.bottom_toolbar.commands) { if (!addCommandInternal(LLCommandId(command_params), mToolbars[LLToolBarEnums::TOOLBAR_BOTTOM])) { diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 221f81e50f..b6dec5b523 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -60,7 +60,12 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llworld.h" -#include "llpanelface.h" +// switchable edit texture/materials panel +// #include "llpanelface.h" +#include "llmaterial.h" +#include "llmaterialmgr.h" +// + #include "lluiusage.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) #include "rlvactions.h" @@ -1411,11 +1416,14 @@ void LLToolDragAndDrop::dropTexture(LLViewerObject* hit_obj, // If user dropped a texture onto face it implies // applying texture now without cancel, save to selection - LLPanelFace* panel_face = gFloaterTools->getPanelFace(); + // LLPanelFace* panel_face = gFloaterTools->getPanelFace(); // switchable edit texture/materials panel if (nodep && gFloaterTools->getVisible() - && panel_face - && panel_face->getTextureDropChannel() == 0 /*texture*/ + // switchable edit texture/materials panel + // && panel_face + // && panel_face->getTextureDropChannel() == 0 /*texture*/ + && gFloaterTools->getTextureDropChannel() == 0 /*texture*/ + // && nodep->mSavedTextures.size() > hit_face) { LLViewerTexture* tex = hit_obj->getTEImage(hit_face); @@ -1458,7 +1466,7 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, LLUUID asset_id = item->getAssetUUID(); - if (hit_obj->getRenderMaterialID(hit_face).notNull() && !remove_pbr) + if (hit_obj->getRenderMaterialID(hit_face).notNull() && !remove_pbr && tex_channel >= -1) // tex_channel -2 means ignorePBR then treat as -1, don't judge me. { // Overrides require textures to be copy and transfer free LLPermissions item_permissions = item->getPermissions(); @@ -1468,16 +1476,28 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, if (allow_adding_to_override) { LLGLTFMaterial::TextureInfo drop_channel = LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR; - LLPanelFace* panel_face = gFloaterTools->getPanelFace(); - if (gFloaterTools->getVisible() && panel_face) + // switchable edit texture/materials panel + // LLPanelFace* panel_face = gFloaterTools->getPanelFace(); + // if (gFloaterTools->getVisible() && panel_face) + // { + // drop_channel = panel_face->getPBRDropChannel(); + // } + if (gFloaterTools->getVisible()) { - drop_channel = panel_face->getPBRDropChannel(); + drop_channel = gFloaterTools->getPBRDropChannel(); } + // set_texture_to_material(hit_obj, hit_face, asset_id, drop_channel); LLGLTFMaterialList::flushUpdates(nullptr); } return; } + // tex_channel -2 means ignorePBR then treat as -1 + if(tex_channel < -1) + { + tex_channel = -1; + } + // BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id); if (!success) { @@ -1494,11 +1514,16 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, LLTextureEntry* tep = hit_obj->getTE(hit_face); - LLPanelFace* panel_face = gFloaterTools->getPanelFace(); + // switchable edit texture/materials panel + // LLPanelFace* panel_face = gFloaterTools->getPanelFace(); - if (gFloaterTools->getVisible() && panel_face) + // if (gFloaterTools->getVisible() && panel_face) + if (gFloaterTools->getVisible()) + // { - tex_channel = (tex_channel > -1) ? tex_channel : panel_face->getTextureDropChannel(); + // switchable edit texture/materials panel + // tex_channel = (tex_channel > -1) ? tex_channel : panel_face->getTextureDropChannel(); + tex_channel = (tex_channel > -1) ? tex_channel : gFloaterTools->getTextureDropChannel(); switch (tex_channel) { @@ -1513,7 +1538,9 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, if (tep) { LLMaterialPtr old_mat = tep->getMaterialParams(); - LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + // switchable edit texture/materials panel + // LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat); new_mat->setNormalID(asset_id); tep->setMaterialParams(new_mat); hit_obj->setTENormalMap(hit_face, asset_id); @@ -1525,7 +1552,9 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, if (tep) { LLMaterialPtr old_mat = tep->getMaterialParams(); - LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + // switchable edit texture/materials panel + // LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat); new_mat->setSpecularID(asset_id); tep->setMaterialParams(new_mat); hit_obj->setTESpecularMap(hit_face, asset_id); diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index 0fa7c6c3a0..66588d2d5a 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -43,8 +43,8 @@ #include "rlvactions.h" // [/RLVa:KB] +// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed // Add control to drag texture faces around -#include "llpanelface.h" #include "llspinctrl.h" #include "llkeyboard.h" #include "llwindow.h" @@ -290,11 +290,14 @@ void LLToolFace::render() LLFloaterTools* toolsFloater=(LLFloaterTools*) LLFloaterReg::findInstance("build"); if(toolsFloater) { - LLPanelFace* panelFace=toolsFloater->mPanelFace; - if(panelFace) - { - panelFace->refresh(); - } + // switchable edit texture/materials panel + // LLPanelFace* panelFace=toolsFloater->mPanelFace; + // if(panelFace) + // { + // panelFace->refresh(); + // } + toolsFloater->refreshPanelFace(); + // } #ifdef TEXTURE_GRAB_UPDATE_REGULARLY diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index d0d4660971..7cf9f2180b 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -87,6 +87,7 @@ #include "llfloaterimsession.h" #include "llfloaterinspect.h" #include "llfloaterinventorysettings.h" +#include "llfloaterinventorythumbnailshelper.h" #include "llfloaterjoystick.h" #include "llfloaterlagmeter.h" #include "llfloaterland.h" @@ -305,6 +306,7 @@ public: "group_picker", "hud", "incoming_call", + "inventory_thumbnails_helper", "linkreplace", "mem_leaking", "marketplace_validation", @@ -401,7 +403,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - + LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); // Optional small camera floater LLFloaterReg::add("fs_camera_small", "floater_fs_camera_small.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -459,6 +461,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("inventory", "floater_my_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("inventory_thumbnails_helper", "floater_inventory_thumbnails_helper.xml", (LLFloaterBuildFunc) &LLFloaterReg::build); LLFloaterReg::add("item_properties", "floater_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("task_properties", "floater_task_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("inventory_settings", "floater_inventory_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index c4d0779668..977591cd86 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -733,15 +733,14 @@ void LLViewerInventoryCategory::setVersion(S32 version) mVersion = version; } -bool LLViewerInventoryCategory::fetch() +bool LLViewerInventoryCategory::fetch(S32 expiry_seconds) { if((VERSION_UNKNOWN == getVersion()) && mDescendentsRequested.hasExpired()) //Expired check prevents multiple downloads. { LL_DEBUGS(LOG_INV) << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL; - const F32 FETCH_TIMER_EXPIRY = 10.0f; mDescendentsRequested.reset(); - mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY); + mDescendentsRequested.setTimerExpirySec(expiry_seconds); std::string url; if (gAgent.getRegion()) @@ -750,7 +749,7 @@ bool LLViewerInventoryCategory::fetch() } else { - LL_WARNS(LOG_INV) << "agent region is null" << LL_ENDL; + LL_WARNS_ONCE(LOG_INV) << "agent region is null" << LL_ENDL; } if (!url.empty() || AISAPI::isAvailable()) { @@ -799,7 +798,13 @@ LLViewerInventoryCategory::EFetchType LLViewerInventoryCategory::getFetching() void LLViewerInventoryCategory::setFetching(LLViewerInventoryCategory::EFetchType fetching) { - if (fetching > mFetching) // allow a switch from normal to recursive + if (fetching == FETCH_FAILED) + { + const F32 FETCH_FAILURE_EXPIRY = 60.0f; + mDescendentsRequested.setTimerExpirySec(FETCH_FAILURE_EXPIRY); + mFetching = fetching; + } + else if (fetching > mFetching) // allow a switch from normal to recursive { if (mDescendentsRequested.hasExpired() || (mFetching == FETCH_NONE)) { diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 10540c8c22..fc71b02894 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -209,13 +209,15 @@ public: S32 getVersion() const; void setVersion(S32 version); - // Returns true if a fetch was issued (not nessesary in progress). - bool fetch(); + // Returns true if a fetch was issued (not nessesary in progress). + // no requests will happen during expiry_seconds even if fetch completed + bool fetch(S32 expiry_seconds = 10); typedef enum { FETCH_NONE = 0, FETCH_NORMAL, FETCH_RECURSIVE, + FETCH_FAILED, // back off } EFetchType; EFetchType getFetching(); // marks as fetch being in progress or as done diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index ad7c4bcefa..03899b6b8f 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -431,7 +431,7 @@ private: private: // a single media url with some data and an impl. - boost::shared_ptr mMediaSource; + std::shared_ptr mMediaSource; LLMutex mLock; F64 mZoomFactor; LLUUID mTextureId; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 525c2ad226..f898fb23a3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -106,6 +106,7 @@ #include "llsceneview.h" #include "llscenemonitor.h" #include "llselectmgr.h" +#include "llsidepanelappearance.h" #include "llspellcheckmenuhandler.h" #include "llstatusbar.h" #include "lltextureview.h" @@ -1659,6 +1660,31 @@ class LLAdvancedCheckDebugUnicode : public view_listener_t +////////////////// +// DEBUG CAMERA // +////////////////// + + +class LLAdvancedToggleDebugCamera : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugCamera = !(LLView::sDebugCamera); + LLFloaterCamera::onDebugCameraToggled(); + return true; + } +}; + +class LLAdvancedCheckDebugCamera : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + return LLView::sDebugCamera; + } +}; + + + /////////////////////// // XUI NAME TOOLTIPS // /////////////////////// @@ -8293,6 +8319,13 @@ void handle_edit_outfit() void handle_now_wearing() { + LLSidepanelAppearance *panel_appearance = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); + if (panel_appearance && panel_appearance->isInVisibleChain() && panel_appearance->isCOFPanelVisible()) + { + LLFloaterReg::findInstance("appearance")->closeFloater(); + return; + } + LLFloaterSidePanelContainer::showPanel("appearance", LLSD().with("type", "now_wearing")); } @@ -12411,6 +12444,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); view_listener_t::addMenu(new LLAdvancedCheckDebugUnicode(), "Advanced.CheckDebugUnicode"); view_listener_t::addMenu(new LLAdvancedToggleDebugUnicode(), "Advanced.ToggleDebugUnicode"); + view_listener_t::addMenu(new LLAdvancedCheckDebugCamera(), "Advanced.CheckDebugCamera"); + view_listener_t::addMenu(new LLAdvancedToggleDebugCamera(), "Advanced.ToggleDebugCamera"); view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index d0a340b6d7..487b5da684 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -146,7 +146,7 @@ public: virtual void notify(const std::vector& filenames); private: - boost::shared_ptr mPlugin; + std::shared_ptr mPlugin; }; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6adf7441cb..1b2044d04c 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -130,8 +130,6 @@ #include "rlvui.h" // [/RLVa:KB] -#include - #include "llnotificationmanager.h" // #include "llexperiencecache.h" @@ -7188,7 +7186,7 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp BOOL caution = FALSE; S32 count = 0; std::string perms; - BOOST_FOREACH(script_perm_t script_perm, SCRIPT_PERMISSIONS) + for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) { // if ((orig_questions & script_perm.permbit) // && script_perm.caution) @@ -7467,7 +7465,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) S32 known_questions = 0; bool has_not_only_debit = questions ^ SCRIPT_PERMISSIONS[SCRIPT_PERMISSION_DEBIT].permbit; // check the received permission flags against each permission - BOOST_FOREACH(script_perm_t script_perm, SCRIPT_PERMISSIONS) + for (const script_perm_t& script_perm : SCRIPT_PERMISSIONS) { if (questions & script_perm.permbit) { diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 352874cf58..38eaeb6288 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -2390,6 +2390,7 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) { LL_WARNS() << objectp->mID << " has self as parent, skipping!" << LL_ENDL; + ++iter; continue; } diff --git a/indra/newview/llviewerparcelaskplay.cpp b/indra/newview/llviewerparcelaskplay.cpp index afbe2c94de..aea06834b2 100644 --- a/indra/newview/llviewerparcelaskplay.cpp +++ b/indra/newview/llviewerparcelaskplay.cpp @@ -287,7 +287,7 @@ void LLViewerParcelAskPlay::saveSettings() if ((iter_parcel->second.mDate.secondsSinceEpoch() + (F64SecondsImplicit)U32Days(30)) > LLTimer::getTotalSeconds()) { // write unexpired parcels - std::string parcel_id = boost::lexical_cast(iter_parcel->first); + std::string parcel_id = std::to_string(iter_parcel->first); write_llsd[key][parcel_id] = LLSD(); write_llsd[key][parcel_id]["mode"] = (LLSD::Integer)iter_parcel->second.mMode; write_llsd[key][parcel_id]["date"] = iter_parcel->second.mDate; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 5084effc59..759d315c9c 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -596,7 +596,7 @@ std::string LLViewerShaderMgr::loadBasicShaders() std::map attribs; attribs["MAX_JOINTS_PER_MESH_OBJECT"] = - boost::lexical_cast(LLSkinningUtil::getMaxJointCount()); + std::to_string(LLSkinningUtil::getMaxJointCount()); BOOL ssr = gSavedSettings.getBOOL("RenderScreenSpaceReflections"); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 2b6ea31d5c..0830dffa5a 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -543,8 +543,8 @@ private: bool mStatesDirty; U32 mCurrResolutionIndex; - boost::scoped_ptr mWindowListener; - boost::scoped_ptr mViewerWindowListener; + std::unique_ptr mWindowListener; + std::unique_ptr mViewerWindowListener; // Object temporarily hovered over while dragging LLPointer mDragHoveredObject; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index c7b9c88059..3185623391 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -4933,6 +4933,15 @@ void LLVOAvatar::updateOrientation(LLAgent& agent, F32 speed, F32 delta_time) if (mTurning) { pelvis_rot_threshold *= 0.4f; + // account for fps, assume that above value is for ~60fps + constexpr F32 default_frame_sec = 0.016f; + F32 prev_frame_sec = LLFrameTimer::getFrameDeltaTimeF32(); + if (default_frame_sec > prev_frame_sec) + { + // reduce threshold since turn rate per second is constant, + // shorter frame means shorter turn. + pelvis_rot_threshold *= prev_frame_sec/default_frame_sec; + } } // am I done turning? diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index a53e783d07..bb67c78a03 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6131,7 +6131,7 @@ void LLVivoxVoiceClient::filePlaybackSetMode(bool vox, float speed) } //------------------------------------------------------------------------ -std::set LLVivoxVoiceClient::sessionState::mSession; +std::set> LLVivoxVoiceClient::sessionState::mSession; LLVivoxVoiceClient::sessionState::sessionState() : diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 2eacc94943..e5edeaae83 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -304,8 +304,8 @@ protected: bool mAvatarIDValid; bool mIsSelf; }; - typedef boost::shared_ptr participantStatePtr_t; - typedef boost::weak_ptr participantStateWptr_t; + typedef std::shared_ptr participantStatePtr_t; + typedef std::weak_ptr participantStateWptr_t; typedef std::map participantMap; typedef std::map participantUUIDMap; @@ -313,10 +313,10 @@ protected: struct sessionState { public: - typedef boost::shared_ptr ptr_t; - typedef boost::weak_ptr wptr_t; + typedef std::shared_ptr ptr_t; + typedef std::weak_ptr wptr_t; - typedef boost::function sessionFunc_t; + typedef std::function sessionFunc_t; static ptr_t createSession(); ~sessionState(); @@ -380,7 +380,7 @@ protected: private: sessionState(); - static std::set mSession; // canonical list of outstanding sessions. + static std::set> mSession; // canonical list of outstanding sessions. std::set::iterator mMyIterator; // used for delete static void for_eachPredicate(const wptr_t &a, sessionFunc_t func); @@ -391,7 +391,7 @@ protected: static bool testByCallerId(const LLVivoxVoiceClient::sessionState::wptr_t &a, LLUUID participantId); }; - typedef boost::shared_ptr sessionStatePtr_t; + typedef std::shared_ptr sessionStatePtr_t; typedef std::map sessionMap; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index c5e7cff9c0..d90e193f09 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4810,6 +4810,11 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& } } + if (getClickAction() == CLICK_ACTION_IGNORE && !LLFloater::isVisible(gFloaterTools)) + { + return FALSE; + } + BOOL ret = FALSE; LLVolume* volume = getVolume(); @@ -5516,6 +5521,10 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, const LLMatrix4* model_mat = NULL; LLDrawable* drawable = facep->getDrawable(); + if(!drawable) + { + return; + } if (rigged) { @@ -5551,6 +5560,15 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, auto* gltf_mat = (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial(); llassert(gltf_mat == nullptr || dynamic_cast(te->getGLTFRenderMaterial()) != nullptr); + + // show legacy when editing the fallback materials. + static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong"); + if( gltf_mat && facep->getViewerObject()->isSelected() && showSelectedinBP ) + { + gltf_mat = nullptr; + } + // + if (gltf_mat != nullptr) { mat_id = gltf_mat->getHash(); // TODO: cache this hash @@ -6781,6 +6799,14 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace const LLTextureEntry* te = facep->getTextureEntry(); LLGLTFMaterial* gltf_mat = te->getGLTFRenderMaterial(); + + // show legacy when editing the fallback materials. + static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong"); + if( gltf_mat && facep->getViewerObject()->isSelected() && showSelectedinBP ) + { + gltf_mat = nullptr; + } + // if (hud_group && gltf_mat == nullptr) { //all hud attachments are fullbright diff --git a/indra/newview/llwindowlistener.cpp b/indra/newview/llwindowlistener.cpp index aa8c79b0d2..0edabf358f 100644 --- a/indra/newview/llwindowlistener.cpp +++ b/indra/newview/llwindowlistener.cpp @@ -388,7 +388,7 @@ static void mouseEvent(const MouseFunc& func, const LLSD& request) LLCoordGL pos(request["x"].asInteger(), request["y"].asInteger()); bool has_pos(request.has("x") && request.has("y")); - boost::scoped_ptr tempfunc; + std::unique_ptr tempfunc; // Documentation for mouseDown(), mouseUp() and mouseMove() claims you // must either specify ["path"], or both of ["x"] and ["y"]. You MAY diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index b816f9a3b5..3c2c6d15c4 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -544,7 +544,7 @@ private: const std::string mMethod; const std::string mReplyPump; LLTempBoundListener mBoundListener; - boost::scoped_ptr mTransaction; + std::unique_ptr mTransaction; LLXMLRPCTransaction::EStatus mPreviousStatus; // To detect state changes. }; diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index ca77dc28b5..72cb002c21 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -188,7 +188,7 @@ public: virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); - typedef boost::shared_ptr ptr_t; + typedef std::shared_ptr ptr_t; private: diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 5978ab7bb8..46f16a9968 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -107,7 +107,7 @@ #include "llfloaterpathfindingconsole.h" #include "llfloaterpathfindingcharacters.h" #include "llfloatertools.h" -#include "llpanelface.h" +// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed #include "llpathfindingpathtool.h" #include "llscenemonitor.h" #include "llprogressview.h" @@ -3660,7 +3660,9 @@ void LLPipeline::postSort(LLCamera &camera) if (!gNonInteractive) { - LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); + // switchable edit texture/materials panel + // LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); + LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getTextureChannelToEdit()); } // Draw face highlights for selected faces. diff --git a/indra/newview/skins/ansastorm/xui/en/floater_camera.xml b/indra/newview/skins/ansastorm/xui/en/floater_camera.xml index 1a8e1977cc..ec8fe13a0f 100644 --- a/indra/newview/skins/ansastorm/xui/en/floater_camera.xml +++ b/indra/newview/skins/ansastorm/xui/en/floater_camera.xml @@ -269,4 +269,22 @@ + + diff --git a/indra/newview/skins/default/xui/az/floater_beacons.xml b/indra/newview/skins/default/xui/az/floater_beacons.xml index 569d019fcb..35be748764 100644 --- a/indra/newview/skins/default/xui/az/floater_beacons.xml +++ b/indra/newview/skins/default/xui/az/floater_beacons.xml @@ -20,7 +20,7 @@ - + Göstərmə istiqaməti: diff --git a/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml index 863f3de86e..e7b294d810 100644 --- a/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml @@ -20,7 +20,7 @@ - + diff --git a/indra/newview/skins/default/xui/az/notifications.xml b/indra/newview/skins/default/xui/az/notifications.xml index 9adbebf57b..326552c1a1 100644 --- a/indra/newview/skins/default/xui/az/notifications.xml +++ b/indra/newview/skins/default/xui/az/notifications.xml @@ -3738,7 +3738,7 @@ Siz [TIME] saniyədən sonra '[BODYREGION]' üçün [RESOLUTION] bişmiş tekstu Siz [TIME] saniyədən sonra '[BODYREGION]' üçün [RESOLUTION] bişmiş teksturasını yerli olaraq yenilədiniz. - Teksturanı yükləmək mümkün deyil. + Teksturanı yükləmək mümkün deyil: '[NAME]' [REASON] diff --git a/indra/newview/skins/default/xui/az/panel_profile_pick.xml b/indra/newview/skins/default/xui/az/panel_profile_pick.xml index 5c4057a6c4..3b7121dd11 100644 --- a/indra/newview/skins/default/xui/az/panel_profile_pick.xml +++ b/indra/newview/skins/default/xui/az/panel_profile_pick.xml @@ -10,8 +10,8 @@ Məkan: Yüklənir... - - + + - \ No newline at end of file + + + diff --git a/indra/newview/skins/default/xui/en/floater_fs_camera_small.xml b/indra/newview/skins/default/xui/en/floater_fs_camera_small.xml index e3365a727b..95fd89d24b 100644 --- a/indra/newview/skins/default/xui/en/floater_fs_camera_small.xml +++ b/indra/newview/skins/default/xui/en/floater_fs_camera_small.xml @@ -411,4 +411,22 @@ free_mode_title + + diff --git a/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml b/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml new file mode 100644 index 0000000000..aa3500bac2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_inventory_thumbnails_helper.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mode + + + + + + + + + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + + Scale + + + + U + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + Scale + + + + U + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + Scale + + + + U + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + Scale + + + + U + + + + + + + + + + V + + + + + + + + + + + + + + Offset + + + + U + + + + + + + + V + + + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + % + + + + Alpha mode + + + + + + + + + + + + + Bumpiness + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shininess + + + + + + + + + + + + + + + + + + + + + + + + + Scale + + + + H + + + + + + + + V + + + + + + + + + + + + Offset + + + + H + + + + + + V + + + + + + + + + + Rotation + + + + + + + + + + + + + + Scale + + + + H + + + + + + + + V + + + + + + + + + + + + Offset + + + + H + + + + + + V + + + + + + + + + + Rotation + + + + + + + + + + + + + + Scale + + + + H + + + + + + + + V + + + + + + + + + + + + Offset + + + + H + + + + + + V + + + + + + + + + + Rotation + + + + + + + + + + + + + + + + URL of chosen media, if any, goes here + + + + +