diff --git a/autobuild.xml b/autobuild.xml index f0e0f7949b..c300fdc6a2 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -922,11 +922,11 @@ archive hash - ff3057e8763bdbe87a478a3d77067b5a + 19e40aa358c1784b49eccd547e704647 hash_algorithm md5 url - file:///opt/firestorm/fmodstudio-2.02.26-darwin64-243641704.tar.bz2 + file:///opt/firestorm/fmodstudio-2.03.07-darwin64-251121740.tar.bz2 name darwin64 @@ -936,11 +936,11 @@ archive hash - 41265f539399e365601a22d108287e91 + a459e2967306ff56a835a321dc00718c hash_algorithm md5 url - file:///opt/firestorm/fmodstudio-2.02.26-linux64-243641703.tar.bz2 + file:///opt/firestorm/fmodstudio-2.03.07-linux64-251121739.tar.bz2 name linux64 @@ -950,11 +950,9 @@ archive hash - 595e7aa51f2161b8d11c3afcc88e2197 - hash_algorithm - md5 + 4a0da36b4a31332df62dadf6438f935e url - file:///c:/cygwin/opt/firestorm/fmodstudio-2.02.26-windows64-243641704.tar.bz2 + file:///c:/cygwin/opt/firestorm/fmodstudio-2.03.07-windows64-251121127.tar.bz2 name windows64 diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 3617ce2bb6..140116fc46 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -140,10 +140,9 @@ public: LLVector3 mHeadOffset{}; // current head position LLAvatarJoint* mRoot{ nullptr }; - // This map gets queried a huge amount of time. + // Joint-lookup improvements // typedef std::map joint_map_t; - typedef std::unordered_map joint_map_t; - // + typedef std::map> joint_map_t; joint_map_t mJointMap; @@ -157,7 +156,7 @@ public: public: typedef std::vector avatar_joint_list_t; const avatar_joint_list_t& getSkeleton() { return mSkeleton; } - typedef std::map joint_alias_map_t; + typedef std::map> joint_alias_map_t; const joint_alias_map_t& getJointAliases(); diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 02d3408497..e9996b93e0 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -44,9 +44,9 @@ #include "sound_ids.h" -const U32 EXTRA_SOUND_CHANNELS = 10; +constexpr U32 EXTRA_SOUND_CHANNELS = 10; -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); +FMOD_RESULT F_CALL windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; @@ -69,13 +69,13 @@ static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) return true; } -LLUUID FMOD_GUID_to_LLUUID(FMOD_GUID guid) +static LLUUID FMOD_GUID_to_LLUUID(FMOD_GUID guid) { return LLUUID(llformat("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7])); } -void set_device(FMOD::System* system, const LLUUID& device_uuid) +static void set_device(FMOD::System* system, const LLUUID& device_uuid) { LL_INFOS() << "LLAudioEngine_FMODSTUDIO::setDevice with device_uuid=" << device_uuid << LL_ENDL; @@ -113,7 +113,7 @@ void set_device(FMOD::System* system, const LLUUID& device_uuid) } } -FMOD_RESULT F_CALLBACK systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata) +FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata) { FMOD::System* sys = (FMOD::System*)system; LLAudioEngine_FMODSTUDIO* audio_engine = (LLAudioEngine_FMODSTUDIO*)userdata; @@ -881,7 +881,7 @@ void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d) // not the main thread. May have implications for callees or audio // engine shutdown. -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) +FMOD_RESULT F_CALL windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) { // inbuffer = fmod's original mixbuffer. // outbuffer = the buffer passed from the previous DSP unit. diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index 20613ea771..68a369b8c2 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -131,7 +131,7 @@ LLQuaternion::Order bvhStringToOrder( char *str ) // LLBVHLoader() //----------------------------------------------------------------------------- -LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map& joint_alias_map ) +LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map>& joint_alias_map ) { reset(); errorLine = 0; @@ -156,9 +156,9 @@ LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &error } // Recognize all names we've been told are legal. - for (std::map::value_type& alias_pair : joint_alias_map) + for (const auto& [alias, joint] : joint_alias_map) { - makeTranslation( alias_pair.first , alias_pair.second ); + makeTranslation(alias, joint); } char error_text[128]; /* Flawfinder: ignore */ diff --git a/indra/llcharacter/llbvhloader.h b/indra/llcharacter/llbvhloader.h index 3fc49a3482..347e8ff416 100644 --- a/indra/llcharacter/llbvhloader.h +++ b/indra/llcharacter/llbvhloader.h @@ -227,7 +227,7 @@ class LLBVHLoader friend class LLKeyframeMotion; public: // Constructor - LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map& joint_alias_map ); + LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine, std::map>& joint_alias_map ); ~LLBVHLoader(); /* diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index b1648397e0..65c70c2ce1 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -77,7 +77,9 @@ LLCharacter::~LLCharacter() //----------------------------------------------------------------------------- // getJoint() //----------------------------------------------------------------------------- -LLJoint *LLCharacter::getJoint( const std::string &name ) +// Joint-lookup improvements +//LLJoint *LLCharacter::getJoint( const std::string &name ) +LLJoint* LLCharacter::getJoint(std::string_view name) { LLJoint* joint = NULL; @@ -94,14 +96,6 @@ LLJoint *LLCharacter::getJoint( const std::string &name ) return joint; } -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// Default fallback is string. -LLJoint *LLCharacter::getJoint( const JointKey &name ) -{ - return getJoint( name.mName ); -} -// - //----------------------------------------------------------------------------- // registerMotion() //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 49880140c4..4efb4bea2d 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -76,13 +76,9 @@ public: // get the specified joint // default implementation does recursive search, // subclasses may optimize/cache results. + // Joint-lookup improvements // virtual LLJoint *getJoint( const std::string &name ); - - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - virtual LLJoint *getJoint( const JointKey &name ); - // - - LLJoint *getJoint( const std::string &name ); + virtual LLJoint* getJoint(std::string_view name); // get the position of the character virtual LLVector3 getCharacterPosition() = 0; diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index 91f33a73eb..7749e2748e 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -34,24 +34,6 @@ #include "llmath.h" #include -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -#include - -std::unordered_map mpStringToKeys; - -JointKey JointKey::construct(const std::string& aName) -{ - if (const auto itr = mpStringToKeys.find(aName); itr != mpStringToKeys.end()) - { - return { aName, itr->second }; - } - - U32 size = static_cast(mpStringToKeys.size()) + 1; - mpStringToKeys.try_emplace(aName, size); - return { aName, size }; -} -// - S32 LLJoint::sNumUpdates = 0; S32 LLJoint::sNumTouches = 0; @@ -260,7 +242,9 @@ LLJoint *LLJoint::getRoot() //----------------------------------------------------------------------------- // findJoint() //----------------------------------------------------------------------------- -LLJoint *LLJoint::findJoint( const std::string &name ) +// Joint-lookup improvements +//LLJoint *LLJoint::findJoint( const std::string &name ) +LLJoint *LLJoint::findJoint(std::string_view name) { if (name == getName()) return this; diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 8118752bfc..f2ceed5f55 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -40,31 +40,6 @@ #include "xform.h" #include "llmatrix4a.h" -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -struct JointKey -{ - std::string mName; - U32 mKey; - - static JointKey construct(const std::string& aName); -}; - -inline bool operator==(JointKey const &aLHS, JointKey const &aRHS) -{ - return aLHS.mName == aRHS.mName; -} - -inline bool operator!=(JointKey const &aLHS, JointKey const &aRHS) -{ - return ! (aLHS == aRHS); -} - -inline std::ostream& operator<<(std::ostream &aLHS, JointKey const &aRHS) -{ - return aLHS << aRHS.mName << " (" << aRHS.mKey << ")"; -} -// - constexpr S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15; // Need to set this to count of animate-able joints, // currently = #bones + #collision_volumes + #attachments + 2, @@ -247,7 +222,9 @@ public: LLJoint *getRoot(); // search for child joints by name - LLJoint *findJoint( const std::string &name ); + // Joint-lookup improvements + //LLJoint *findJoint( const std::string &name ); + LLJoint* findJoint(std::string_view name); // add/remove children void addChild( LLJoint *joint ); diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index fcecc46f84..6a3d1ecf88 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -91,7 +91,7 @@ U32 micro_sleep(U64 us, U32 max_yields) U32 micro_sleep(U64 us, U32 max_yields) { - LL_PROFILE_ZONE_SCOPED; + // LL_PROFILE_ZONE_SCOPED; // remove pointless profiling #if 0 LARGE_INTEGER ft; ft.QuadPart = -static_cast(us * 10); // '-' using relative time @@ -109,7 +109,7 @@ U32 micro_sleep(U64 us, U32 max_yields) void ms_sleep(U32 ms) { - LL_PROFILE_ZONE_SCOPED; + // LL_PROFILE_ZONE_SCOPED; // remove pointless profiling micro_sleep(ms * 1000, 0); } diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index 5880fb7e87..8e72edd2cf 100644 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -292,7 +292,7 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread) ELoopSpeed loop(REQUEST_SLEEP); while (! mExitRequested) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + // LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; // remove pointless profiling try { loop = processRequestQueue(loop); diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index 725f04b1f2..2f96c1ded4 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -333,11 +333,21 @@ const std::string LLDiskCache::metaDataToFilepath(const LLUUID& id, LLAssetType: const std::string LLDiskCache::getCacheInfo() { + LL_PROFILE_ZONE_SCOPED; // add some instrumentation std::ostringstream cache_info; F32 max_in_mb = (F32)mMaxSizeBytes / (1024.0f * 1024.0f); - F32 percent_used = ((F32)dirFileSize(sCacheDir) / (F32)mMaxSizeBytes) * 100.0f; - + // stall prevention. We still need to make sure this initialised when called at startup. + F32 percent_used; + if (mStoredCacheSize > 0) + { + percent_used = ((F32)mStoredCacheSize / (F32)mMaxSizeBytes) * 100.0f; + } + else + { + percent_used = ((F32)dirFileSize(sCacheDir) / (F32)mMaxSizeBytes) * 100.0f; + } + // cache_info << std::fixed; cache_info << std::setprecision(1); cache_info << "Max size " << max_in_mb << " MB "; diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp index 3103ce90dd..b3f0530af5 100644 --- a/indra/llmath/llcamera.cpp +++ b/indra/llmath/llcamera.cpp @@ -35,7 +35,7 @@ LLCamera::LLCamera() : LLCoordFrame(), mView(DEFAULT_FIELD_OF_VIEW), mAspect(DEFAULT_ASPECT_RATIO), - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //mInverseAspect(1.0f / DEFAULT_ASPECT_RATIO), mDrawDistanceMultiplier(1.0f), // [FIRE-35081] @@ -67,14 +67,14 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p } mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Store the inverse of the aspect ratio, so we can remove it from texture calculations //mInverseAspect = 1.0f / mAspect; // [FIRE-35081] mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE); if(far_plane < 0) far_plane = DEFAULT_FAR_PLANE; mFarPlane = llclamp(far_plane, MIN_FAR_PLANE, MAX_FAR_PLANE); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Store the draw distance multiplier based upon how much bigger/smaller the far plan is then the default (64.0f) mDrawDistanceMultiplier = mFarPlane / DEFAULT_FAR_PLANE; mDrawDistanceMultiplier = mDrawDistanceMultiplier < 1.0f ? 1.0f : mDrawDistanceMultiplier; @@ -141,7 +141,7 @@ void LLCamera::setViewHeightInPixels(S32 height) void LLCamera::setAspect(F32 aspect_ratio) { mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Store the inverse of the aspect ratio, so we can remove it from texture calculations //mInverseAspect = 1.0f / mAspect; // [FIRE-35081] @@ -159,7 +159,7 @@ void LLCamera::setNear(F32 near_plane) void LLCamera::setFar(F32 far_plane) { mFarPlane = llclamp(far_plane, MIN_FAR_PLANE, MAX_FAR_PLANE); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Store the draw distance multiplier based upon how much bigger/smaller the far plan is then the default (64.0f) mDrawDistanceMultiplier = mFarPlane / DEFAULT_FAR_PLANE; mDrawDistanceMultiplier = mDrawDistanceMultiplier < 1.0f ? 1.0f : mDrawDistanceMultiplier; diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index cfe2227620..ea6a303032 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -127,7 +127,7 @@ private: F32 mView; // angle between top and bottom frustum planes in radians. F32 mAspect; // width/height - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Store the inverse of the aspect ratio, for the texture's sizes //F32 mInverseAspect; // height/width F32 mDrawDistanceMultiplier; // mFarPlane / DEFAULT_FAR_PLANE @@ -166,7 +166,7 @@ public: F32 getView() const { return mView; } // vertical FOV in radians S32 getViewHeightInPixels() const { return mViewHeightInPixels; } F32 getAspect() const { return mAspect; } // width / height - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //F32 getInverseAspect() const { return mInverseAspect; } // width / height F32 getDrawDistanceMultiplier() const { return mDrawDistanceMultiplier; } // mFarPlane / DEFAULT_FAR_PLANE (could also include near plane as well) // [FIRE-35081] diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 5c37fee62c..4843ed83f1 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -113,10 +113,11 @@ class LLMessageHandlerBridge : public LLHTTPNode void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"]; char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str()); - LL_DEBUGS() << "Setting mLastSender " << input["sender"].asString() << LL_ENDL; + LL_DEBUGS("Messaging") << "Setting mLastSender " << input["sender"].asString() << LL_ENDL; gMessageSystem->mLastSender = LLHost(input["sender"].asString()); gMessageSystem->mPacketsIn += 1; gMessageSystem->mLLSDMessageReader->setMessage(namePtr, input["body"]); @@ -2050,6 +2051,7 @@ void LLMessageSystem::dispatch( const std::string& msg_name, const LLSD& message) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; LLPointer responsep = LLSimpleResponse::create(); dispatch(msg_name, message, responsep); } @@ -2060,6 +2062,7 @@ void LLMessageSystem::dispatch( const LLSD& message, LLHTTPNode::ResponsePtr responsep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; if ((gMessageSystem->mMessageTemplates.find (LLMessageStringTable::getInstance()->getString(msg_name.c_str())) == gMessageSystem->mMessageTemplates.end()) && diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index c3c3f81ea2..d0ff1945ea 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -917,7 +917,7 @@ LLDAELoader::LLDAELoader( void* opaque_userdata, JointTransformMap& jointTransformMap, JointNameSet& jointsFromNodes, - std::map& jointAliasMap, + std::map>& jointAliasMap, U32 maxJointsPerMesh, U32 modelLimit, // mesh loader suffix configuration @@ -1467,10 +1467,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do { name = mJointMap[name]; } -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// model->mSkinInfo.mJointNames.push_back( name ); - model->mSkinInfo.mJointNames.push_back( JointKey::construct( name ) ); -// + model->mSkinInfo.mJointNames.push_back(name); model->mSkinInfo.mJointNums.push_back(-1); } } @@ -1488,10 +1485,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do { name = mJointMap[name]; } -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// model->mSkinInfo.mJointNames.push_back( name ); - model->mSkinInfo.mJointNames.push_back( JointKey::construct( name ) ); -// + model->mSkinInfo.mJointNames.push_back(name); model->mSkinInfo.mJointNums.push_back(-1); } } @@ -1533,10 +1527,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do //but does not use the skeleton). buildJointToNodeMappingFromScene( root ); -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames ); - critiqueRigForUploadApplicability( toStringVector( model->mSkinInfo.mJointNames ) ); -// + critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames ); if ( !missingSkeletonOrScene ) { @@ -1589,11 +1580,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do //with the skeleton are not stored in the same order as they are in the exported joint buffer. //This remaps the skeletal joints to be in the same order as the joints stored in the model. -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - // std::vector ::const_iterator jointIt = model->mSkinInfo.mJointNames.begin(); - std::vector< std::string > jointNames = toStringVector( model->mSkinInfo.mJointNames ); - std::vector ::const_iterator jointIt = jointNames.begin(); -// + std::vector ::const_iterator jointIt = model->mSkinInfo.mJointNames.begin(); const int jointCnt = static_cast(model->mSkinInfo.mJointNames.size()); for ( int i=0; i& jointAliasMap, - U32 maxJointsPerMesh, - U32 modelLimit, + std::string filename, + S32 lod, + LLModelLoader::load_callback_t load_cb, + LLModelLoader::joint_lookup_func_t joint_lookup_func, + LLModelLoader::texture_load_func_t texture_load_func, + LLModelLoader::state_callback_t state_cb, + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + std::map>& jointAliasMap, + U32 maxJointsPerMesh, + U32 modelLimit, // configrable lod suffix support - // bool preprocess); - bool preprocess, - const LODSuffixArray& lod_suffix); + // bool preprocess); + bool preprocess, + const LODSuffixArray& lod_suffix); // virtual ~LLDAELoader() ; diff --git a/indra/llprimitive/llgltfloader.cpp b/indra/llprimitive/llgltfloader.cpp index 480012699a..724b1a88b2 100644 --- a/indra/llprimitive/llgltfloader.cpp +++ b/indra/llprimitive/llgltfloader.cpp @@ -66,19 +66,19 @@ static const std::string lod_suffix[LLModel::NUM_LODS] = }; -LLGLTFLoader::LLGLTFLoader(std::string filename, - S32 lod, - LLModelLoader::load_callback_t load_cb, - LLModelLoader::joint_lookup_func_t joint_lookup_func, - LLModelLoader::texture_load_func_t texture_load_func, - LLModelLoader::state_callback_t state_cb, - void * opaque_userdata, - JointTransformMap & jointTransformMap, - JointNameSet & jointsFromNodes, - std::map &jointAliasMap, - U32 maxJointsPerMesh, - U32 modelLimit) //, - //bool preprocess) +LLGLTFLoader::LLGLTFLoader(std::string filename, + S32 lod, + LLModelLoader::load_callback_t load_cb, + LLModelLoader::joint_lookup_func_t joint_lookup_func, + LLModelLoader::texture_load_func_t texture_load_func, + LLModelLoader::state_callback_t state_cb, + void * opaque_userdata, + JointTransformMap & jointTransformMap, + JointNameSet & jointsFromNodes, + std::map> & jointAliasMap, + U32 maxJointsPerMesh, + U32 modelLimit) //, + //bool preprocess) : LLModelLoader( filename, lod, load_cb, diff --git a/indra/llprimitive/llgltfloader.h b/indra/llprimitive/llgltfloader.h index 66671d1c5a..848a07c1e4 100644 --- a/indra/llprimitive/llgltfloader.h +++ b/indra/llprimitive/llgltfloader.h @@ -121,18 +121,18 @@ class LLGLTFLoader : public LLModelLoader typedef std::map material_map; LLGLTFLoader(std::string filename, - S32 lod, - LLModelLoader::load_callback_t load_cb, - LLModelLoader::joint_lookup_func_t joint_lookup_func, - LLModelLoader::texture_load_func_t texture_load_func, - LLModelLoader::state_callback_t state_cb, - void * opaque_userdata, - JointTransformMap & jointTransformMap, - JointNameSet & jointsFromNodes, - std::map &jointAliasMap, - U32 maxJointsPerMesh, - U32 modelLimit); //, - //bool preprocess ); + S32 lod, + LLModelLoader::load_callback_t load_cb, + LLModelLoader::joint_lookup_func_t joint_lookup_func, + LLModelLoader::texture_load_func_t texture_load_func, + LLModelLoader::state_callback_t state_cb, + void * opaque_userdata, + JointTransformMap & jointTransformMap, + JointNameSet & jointsFromNodes, + std::map> &jointAliasMap, + U32 maxJointsPerMesh, + U32 modelLimit); //, + //bool preprocess ); virtual ~LLGLTFLoader(); virtual bool OpenFile(const std::string &filename); diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 4c101068a1..134bc331b2 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -1501,10 +1501,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) { for (U32 i = 0; i < skin["joint_names"].size(); ++i) { -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// mJointNames.push_back( skin[ "joint_names" ][ i ] ); - mJointNames.push_back( JointKey::construct( skin[ "joint_names" ][ i ] ) ); -// ND> + mJointNames.push_back( skin[ "joint_names" ][ i ] ); mJointNums.push_back(-1); } } @@ -1594,10 +1591,7 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi for (U32 i = 0; i < mJointNames.size(); ++i) { -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// ret[ "joint_names" ][ i ] = mJointNames[ i ]; - ret[ "joint_names" ][ i ] = mJointNames[ i ].mName; -// + ret[ "joint_names" ][ i ] = mJointNames[ i ]; for (U32 j = 0; j < 4; j++) { @@ -1648,9 +1642,7 @@ void LLMeshSkinInfo::updateHash() //mJointNames for (auto& name : mJointNames) { - // Joint lookup speedup - //hash.update(name); - hash.update(name.mName); + hash.update(name); } //mJointNums @@ -1676,10 +1668,7 @@ U32 LLMeshSkinInfo::sizeBytes() const res += sizeof(std::vector) + sizeof(std::string) * static_cast(mJointNames.size()); for (U32 i = 0; i < mJointNames.size(); ++i) { - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //res += static_cast(mJointNames[i].size()); // actual size, not capacity - res += static_cast(mJointNames[i].mName.size()); // actual size, not capacity - // + res += static_cast(mJointNames[i].size()); // actual size, not capacity } res += sizeof(std::vector) + sizeof(S32) * static_cast(mJointNums.size()); diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 816ca3d000..010b6d5d85 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -56,10 +56,7 @@ public: U32 sizeBytes() const; LLUUID mMeshID; -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// std::vector mJointNames; - std::vector< JointKey > mJointNames; -// + std::vector mJointNames; mutable std::vector mJointNums; typedef std::vector matrix_list_t; matrix_list_t mInvBindMatrix; diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index d3fa1767a5..39b6c81be9 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -257,10 +257,7 @@ bool LLModelLoader::loadFromSLM(const std::string& filename) if (!loaded_model->mSkinInfo.mJointNames.empty()) { //check to see if rig is valid -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames ); - critiqueRigForUploadApplicability( toStringVector( loaded_model->mSkinInfo.mJointNames ) ); -// + critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames ); } else if (mCacheOnlyHitIfRigged) { diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index d04585bd2c..357672aa4e 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -36,7 +36,7 @@ class LLJoint; typedef std::map JointTransformMap; typedef std::map::iterator JointTransformMapIt; -typedef std::map JointMap; +typedef std::map> JointMap; typedef std::deque JointNameSet; const S32 SLM_SUPPORTED_VERSION = 3; @@ -196,18 +196,6 @@ public: void clearLog() { mWarningsArray.clear(); } protected: -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - std::vector< std::string > toStringVector( std::vector< JointKey > const &aIn ) const - { - std::vector< std::string > out; - - for( std::vector< JointKey >::const_iterator itr = aIn.begin(); itr != aIn.end(); ++itr ) - out.push_back( itr->mName ); - - return out; - } -// - LLModelLoader::load_callback_t mLoadCallback; LLModelLoader::joint_lookup_func_t mJointLookupFunc; LLModelLoader::texture_load_func_t mTextureLoadFunc; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 781d0fce43..8f74da47b2 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -1074,6 +1074,7 @@ void LLGLManager::initWGL() // return false if unable (or unwilling due to old drivers) to init GL bool LLGLManager::initGL() { + LL_INFOS("RenderInit") << "Initializing OpenGL" << LL_ENDL; // Extra logging to confirm usage on Linux if (mInited) { LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL; @@ -1514,6 +1515,11 @@ void LLGLManager::initExtensions() mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); //Basic AMD method, also see mHasAMDAssociations LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; +// FIRE-34655 - VRAM detection failing on Linux. Load all the GL functions we need. +#if LL_LINUX && !LL_MESA_HEADLESS + mHasNVXGpuMemoryInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); + mHasAMDAssociations = ExtensionExists("WGL_AMD_gpu_association", gGLHExts.mSysExts); +#endif #if LL_WINDOWS // diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index b3f32fdc83..c682b0493a 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1076,8 +1076,8 @@ void LLGLSLShader::bind() void LLGLSLShader::bind(U8 variant) { - llassert(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS); - llassert(variant < LLGLSLShader::NUM_GLTF_VARIANTS); + llassert_always(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS); + llassert_always(variant < LLGLSLShader::NUM_GLTF_VARIANTS); mGLTFVariants[variant].bind(); } @@ -1085,7 +1085,7 @@ void LLGLSLShader::bind(bool rigged) { if (rigged) { - llassert(mRiggedVariant); + llassert_always(mRiggedVariant); mRiggedVariant->bind(); } else diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index 5f645b9d76..377e453ba4 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -104,7 +104,7 @@ void LLGLTexture::setBoostLevel(S32 level) if(mBoostLevel != LLGLTexture::BOOST_NONE && mBoostLevel != LLGLTexture::BOOST_ICON && mBoostLevel != LLGLTexture::BOOST_THUMBNAIL - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Add the new grass, light and tree boosts && mBoostLevel != LLGLTexture::BOOST_GRASS && mBoostLevel != LLGLTexture::BOOST_LIGHT diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 65911e92a7..4336039c1c 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -53,7 +53,7 @@ public: BOOST_AVATAR_BAKED , BOOST_TERRAIN , // Needed for minimap generation for now. Lower than BOOST_HIGH so the texture stats don't get forced, i.e. texture stats are manually managed by minimap/terrain instead. - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings BOOST_GRASS , // Grass has a alternative calculation for virtual and face sizes. BOOST_TREE , // Tree has a alternative calculation for virtual and face sizes. BOOST_LIGHT , // Light textures has a alternative calculation for virtual and face sizes. diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp index d810d365bc..0842c90409 100644 --- a/indra/llui/llconsole.cpp +++ b/indra/llui/llconsole.cpp @@ -565,7 +565,7 @@ void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, L { if ( !force_resize ) { - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // if ( mMaxWidth >= 0.0f //&& mMaxWidth < screen_width) // If viewer window was made as small as possible with the console enabled, it would cause an assert error diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 68b619f4b4..a3d57f6690 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1530,7 +1530,19 @@ void LLTextBase::draw() bg_rect.intersectWith( text_rect ); gl_rect_2d( text_rect, bg_color, true ); + + // Additionally set the font color of highlighted text instead of using LabelTextColor + const LLColor4& font_color = ll::ui::SearchableControl::getHighlightFontColor(); + setColor(font_color); + // } + // Set the font color back to LabelTextColor if not highlighted + else + { + const LLColor4& font_color = LLUIColorTable::instance().getColor("LabelTextColor"); + setColor(font_color); + } + // bool should_clip = mClip || mScroller != NULL; // Fix text bleeding at top edge of scrolling text editors diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 01f1b8eb9a..e1b917deb8 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -1249,7 +1249,7 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) // LLUrlEntryPlace::LLUrlEntryPlace() { - mPattern = boost::regex("((hop://[-\\w\\.\\:\\@]+/)|((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://)))\\S+(?:/?(-?\\d+/-?\\d+/-?\\d+|-?\\d+/-?\\d+)/?)?", // + mPattern = boost::regex("(((hop://[-\\w\\.\\:\\@]+/)|((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://)))\\S+/?(\\d+/\\d+/-?\\d+|\\d+/-?\\d+)/?)|(hop://[-\\w\\.\\:\\@]+/[^\\s/]+/?(?![^\\s]))", // boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index a033c72910..f394989f19 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -266,7 +266,15 @@ U32 LLDXHardware::getMBVideoMemoryViaWMI() //Getting the version of graphics controller driver via WMI std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor) { - std::string mDriverVersion; + // Add caching for WMI query results + LL_PROFILE_ZONE_SCOPED; + static auto driver_version = std::string(); + + if (!driver_version.empty()) + { + return driver_version; // Return cached version + } + // HRESULT hres; CoInitializeEx(0, COINIT_APARTMENTTHREADED); IWbemLocator *pLoc = NULL; @@ -435,11 +443,11 @@ std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor) std::string str = ll_convert_wide_to_string(ws); LL_INFOS("AppInit") << " DriverVersion : " << str << LL_ENDL; - if (mDriverVersion.empty()) + if (driver_version.empty()) // caching version (also make the varname not stupid) { - mDriverVersion = str; + driver_version = str; // caching version (also make the varname not stupid) } - else if (mDriverVersion != str) + else if (driver_version != str) // caching version (also make the varname not stupid) { if (vendor == GPU_ANY) { @@ -475,7 +483,7 @@ std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor) // supposed to always call CoUninitialize even if init returned false CoUninitialize(); - return mDriverVersion; + return driver_version; // caching version of driver query } void get_wstring(IDxDiagContainer* containerp, const WCHAR* wszPropName, WCHAR* wszPropValue, int outputSize) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 84e3fad927..23bdb6439f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -96,6 +96,7 @@ set(viewer_SOURCE_FILES dialogstack.cpp exoflickr.cpp exoflickrauth.cpp + fsprimfeedauth.cpp exogroupmutelist.cpp floatermedialists.cpp fsareasearch.cpp @@ -164,6 +165,7 @@ set(viewer_SOURCE_FILES fspose.cpp fsposeranimator.cpp fsposingmotion.cpp + fsprimfeedauth.cpp fsradar.cpp fsradarentry.cpp fsradarlistctrl.cpp @@ -182,6 +184,8 @@ set(viewer_SOURCE_FILES lfsimfeaturehandler.cpp llflickrconnect.cpp llfloaterflickr.cpp + fsprimfeedconnect.cpp + fsfloaterprimfeed.cpp llpanelopenregionsettings.cpp # [Legacy Bake] llagentwearablesfetch.cpp @@ -910,6 +914,7 @@ set(viewer_HEADER_FILES dialogstack.h exoflickr.h exoflickrauth.h + fsprimfeedauth.h exogroupmutelist.h floatermedialists.h fsareasearch.h @@ -980,6 +985,7 @@ set(viewer_HEADER_FILES fspose.h fsposeranimator.h fsposingmotion.h + fsprimfeedauth.h fsradar.h fsradarentry.h fsradarlistctrl.h @@ -999,6 +1005,8 @@ set(viewer_HEADER_FILES lfsimfeaturehandler.h llflickrconnect.h llfloaterflickr.h + fsprimfeedconnect.h + fsfloaterprimfeed.h # [Legacy Bake] llagentwearablesfetch.h vjlocalmesh.h diff --git a/indra/newview/ao.cpp b/indra/newview/ao.cpp index f0fb99875f..f3b3e390f7 100644 --- a/indra/newview/ao.cpp +++ b/indra/newview/ao.cpp @@ -871,8 +871,23 @@ void FloaterAO::onAnimationChanged(const LLUUID& animation) if (mCurrentBoldItem) { - ((LLScrollListIcon*)mCurrentBoldItem->getColumn(0))->setValue("FSAO_Animation_Stopped"); - ((LLScrollListText*)mCurrentBoldItem->getColumn(1))->setFontStyle(LLFontGL::NORMAL); +// Safer casts + if (LLScrollListCell* icon_cell = mCurrentBoldItem->getColumn(0)) + { + if (LLScrollListIcon* icon = dynamic_cast(icon_cell)) + { + icon->setValue("FSAO_Animation_Stopped"); + } + } + + if (LLScrollListCell* text_cell = mCurrentBoldItem->getColumn(1)) + { + if (LLScrollListText* text = dynamic_cast(text_cell)) + { + text->setFontStyle(LLFontGL::NORMAL); + } + } +// mCurrentBoldItem = nullptr; } @@ -882,21 +897,46 @@ void FloaterAO::onAnimationChanged(const LLUUID& animation) return; } - // why do we have no LLScrollListCtrl::getItemByUserdata() ? -Zi - for (auto item : mAnimationList->getAllData()) +// Fix potential nullptr + if (!mAnimationList) { - LLUUID* id = (LLUUID*)item->getUserdata(); + LL_WARNS("AO") << "Animation list control is null." << LL_ENDL; + return; + } +// - if (id == &animation) +// Safer casts + // why do we have no LLScrollListCtrl::getItemByUserdata() ? -Zi + for (LLScrollListItem* item : mAnimationList->getAllData()) + { + LLUUID* id = static_cast(item->getUserdata()); + // compares the LLUUID values instead of pointer values + //if (id == &animation) + if (id && *id == animation) + // { mCurrentBoldItem = item; - ((LLScrollListIcon*)mCurrentBoldItem->getColumn(0))->setValue("FSAO_Animation_Playing"); - ((LLScrollListText*)mCurrentBoldItem->getColumn(1))->setFontStyle(LLFontGL::BOLD); + if (LLScrollListCell* icon_cell = mCurrentBoldItem->getColumn(0)) + { + if (LLScrollListIcon* icon = dynamic_cast(icon_cell)) + { + icon->setValue("FSAO_Animation_Playing"); + } + } + + if (LLScrollListCell* text_cell = mCurrentBoldItem->getColumn(1)) + { + if (LLScrollListText* text = dynamic_cast(text_cell)) + { + text->setFontStyle(LLFontGL::BOLD); + } + } return; } } +// } // virtual diff --git a/indra/newview/aoengine.cpp b/indra/newview/aoengine.cpp index a66c8885b8..19b53d3ba1 100644 --- a/indra/newview/aoengine.cpp +++ b/indra/newview/aoengine.cpp @@ -999,6 +999,13 @@ void AOEngine::playAnimation(const LLUUID& animation) } LLViewerInventoryItem* item = gInventory.getItem(animation); + + if (!item) + { + LL_WARNS("AOEngine") << "Inventory item for animation " << animation << " not found." << LL_ENDL; + return; + } + AOSet::AOAnimation anim; anim.mName = item->LLInventoryItem::getName(); anim.mInventoryUUID = item->getUUID(); @@ -1007,12 +1014,21 @@ void AOEngine::playAnimation(const LLUUID& animation) // if we can find the original animation already right here, save its asset ID, otherwise this will // be tried again in AOSet::getAnimationForState() and/or AOEngine::cycle() + LLUUID newAnimation; if (item->getLinkedItem()) { - anim.mAssetUUID = item->getAssetUUID(); + newAnimation = item->getAssetUUID(); + //anim.mAssetUUID = item->getAssetUUID(); } - LLUUID newAnimation = anim.mAssetUUID; + if (newAnimation.isNull()) + { + LL_WARNS("AOEngine") << "New animation UUID is null for animation " << animation << LL_ENDL; + return; + } + anim.mAssetUUID = newAnimation; + + //LLUUID newAnimation = anim.mAssetUUID; LLUUID oldAnimation = state->mCurrentAnimationID; // don't do anything if the animation didn't change @@ -1024,7 +1040,7 @@ void AOEngine::playAnimation(const LLUUID& animation) mAnimationChangedSignal(LLUUID::null); // Searches for the index of the animation - U32 idx = -1; + S32 idx = -1; for (U32 i = 0; i < state->mAnimations.size(); i++) { if (state->mAnimations[i].mAssetUUID == newAnimation) @@ -1033,18 +1049,22 @@ void AOEngine::playAnimation(const LLUUID& animation) break; } } - if (idx < 0) + if (idx == -1) { - idx = 0; + LL_WARNS("AOEngine") << "Animation index not found for animation " << animation << LL_ENDL; + return; } - state->mCurrentAnimation = idx; + state->mCurrentAnimation = static_cast(idx); state->mCurrentAnimationID = newAnimation; if (newAnimation.notNull()) { LL_DEBUGS("AOEngine") << "requesting animation start for motion " << gAnimLibrary.animationName(mLastMotion) << ": " << newAnimation << LL_ENDL; gAgent.sendAnimationRequest(newAnimation, ANIM_REQUEST_START); - mAnimationChangedSignal(state->mAnimations[state->mCurrentAnimation].mInventoryUUID); + if (state->mCurrentAnimation < state->mAnimations.size()) + { + mAnimationChangedSignal(state->mAnimations[state->mCurrentAnimation].mInventoryUUID); + } } else { diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 7708f9a0c9..7f26b29024 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -254,6 +254,16 @@ is_running_function="Floater.IsOpen" is_running_parameters="flickr" /> + Value http://phoenixviewer.com/app/fsdata/grids.xml + FSPrimfeedViewerApiKey + + Comment + Viewer key for API login. + Persist + 1 + Type + String + Value + xAcXYt8SBius3Lor4wHle8L96PDHYlAZuWYXIYQUdW4b09mjhQUAwiqmWp5UNYXLpq5GSUtuKHuDYLwaueACPkew93l6MRY8jfBKSH09kv0zyGglpky07X7X7Sp4Rzin + FSGridBuilderURL Comment @@ -18553,6 +18564,7 @@ Change of this parameter will affect the layout of buttons in notification toast world_map preferences flickr + primfeed Backup 0 @@ -24806,6 +24818,39 @@ Change of this parameter will affect the layout of buttons in notification toast Value 4 + FSLastSnapshotToPrimfeedHeight + + Comment + The height of the last Primfeed snapshot, in px + Persist + 1 + Type + S32 + Value + 768 + + FSLastSnapshotToPrimfeedWidth + + Comment + The width of the last Primfeed snapshot, in px + Persist + 1 + Type + S32 + Value + 1024 + + FSLastSnapshotToPrimfeedResolution + + Comment + At what resolution should snapshots be posted on Primfeed. 0=Current Window, 1=320x240, 2=640x480, 3=800x600, 4=1024x768, 5=1280x1024, 6=1600x1200, 7=Custom + Persist + 1 + Type + S32 + Value + 4 + FSLastSnapshotToTwitterHeight Comment @@ -25092,6 +25137,19 @@ Change of this parameter will affect the layout of buttons in notification toast Value 1 + FSNoVersionPopup + + Comment + Disables version popup on the Firestorm Login page + Persist + 1 + Type + Boolean + Value + 0 + HideFromEditor + 1 + FSllOwnerSayToScriptDebugWindowRouting Comment @@ -26365,5 +26423,27 @@ Change of this parameter will affect the layout of buttons in notification toast Value 0 + FSSnapshotLocalNamesWithTimestamps + + Comment + include a timestamp in the filename when saving snapshots locally + Persist + 1 + Type + Boolean + Value + 1 + + FSRepeatedEnvTogglesShared + + Comment + Whether repeated presses of sky preset shortcuts should revert to shared environment + Persist + 1 + Type + Boolean + Value + 0 + diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index 25360ec2d9..df421cadb1 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -1358,6 +1358,83 @@ Value 0 + FSPrimfeedOAuthToken + + Comment + contains the secure authentication toke to post to your primfeed account (do not share) + Persist + 1 + Type + String + Value + + + FSPrimfeedProfileLink + + Comment + The profile page for the account associated with the currently linked Primfeed account + Persist + 1 + Type + String + Value + + + FSPrimfeedPlan + + Comment + The plan type associated with the currently linked Primfeed account + Persist + 1 + Type + String + Value + + + FSPrimfeedUsername + + Comment + The username associated with the currently linked Primfeed account + Persist + 1 + Type + String + Value + + + FSPrimfeedCommercialContent + + Comment + Does this post contain commercial content + Persist + 1 + Type + Boolean + Value + 0 + + FSPrimfeedAddToPublicGallery + + Comment + Should this post go to the public gallery? + Persist + 0 + Type + Boolean + Value + 0 + + FSPrimfeedOpenURLOnPost + + Comment + if true open the URL in a browser when the post completes + Persist + 1 + Type + Boolean + Value + 0 + FSProtectedFolders Comment @@ -1369,5 +1446,49 @@ Value + FSPrimfeedPhotoRating + + Comment + Content rating to be shared with Primfeed. + Persist + 1 + Type + Integer + Value + 1 + + FSPrimfeedPhotoResolution + + Comment + Last used resolution for Primfeed photos. + Persist + 1 + Type + LLSD + Value + + + FlickrPhotoResolution + + Comment + Last used resolution for Primfeed photos. + Persist + 1 + Type + LLSD + Value + + + FlickrPhotoRating + + Comment + Content rating to be shared with Flickr. + Persist + 1 + Type + Integer + Value + 1 + diff --git a/indra/newview/bugsplatattributes.cpp b/indra/newview/bugsplatattributes.cpp index 1852f9de3f..d0a8b32701 100644 --- a/indra/newview/bugsplatattributes.cpp +++ b/indra/newview/bugsplatattributes.cpp @@ -64,6 +64,7 @@ std::string BugSplatAttributes::to_xml_token(const std::string& input) bool BugSplatAttributes::writeToFile(const std::string& file_path) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; std::lock_guard lock(mMutex); // Write to a temporary file first @@ -91,6 +92,7 @@ bool BugSplatAttributes::writeToFile(const std::string& file_path) } // Write out all other categories + // BugSplat chaanged the XML format and there is no strict category support now. For now we'll prefix the category to each attribute for (const auto& cat_pair : mAttributes) { const std::string& category = cat_pair.first; @@ -101,14 +103,12 @@ bool BugSplatAttributes::writeToFile(const std::string& file_path) continue; } - ofs << " <" << category << ">\n"; for (const auto& kv : cat_pair.second) { const std::string& key = kv.first; const std::string& val = kv.second; - ofs << " <" << key << ">" << val << "\n"; + ofs << " <" << category << "-" << key << ">" << val << "\n"; } - ofs << " \n"; } ofs << "\n"; diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 442fe4ce75..c2aeba6334 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -333,7 +333,7 @@ RenderReflectionProbeLevel 1 3 RenderMirrors 1 0 RenderHeroProbeResolution 1 1024 RenderHeroProbeDistance 1 16 -RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeUpdateRate 1 2 RenderHeroProbeConservativeUpdateMultiplier 1 4 RenderCASSharpness 1 0.4 RenderExposure 1 1 @@ -375,7 +375,7 @@ RenderReflectionProbeLevel 1 3 RenderMirrors 1 0 RenderHeroProbeResolution 1 2048 RenderHeroProbeDistance 1 16 -RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeUpdateRate 1 2 RenderHeroProbeConservativeUpdateMultiplier 1 4 RenderCASSharpness 1 0.4 RenderExposure 1 1 diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index b1c2b3cf55..ecb1036c0b 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -333,7 +333,7 @@ RenderReflectionProbeLevel 1 3 RenderMirrors 1 0 RenderHeroProbeResolution 1 1024 RenderHeroProbeDistance 1 16 -RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeUpdateRate 1 2 RenderHeroProbeConservativeUpdateMultiplier 1 4 RenderCASSharpness 1 0.4 RenderExposure 1 1 @@ -375,7 +375,7 @@ RenderReflectionProbeLevel 1 3 RenderMirrors 1 0 RenderHeroProbeResolution 1 2048 RenderHeroProbeDistance 1 16 -RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeUpdateRate 1 2 RenderHeroProbeConservativeUpdateMultiplier 1 4 RenderCASSharpness 1 0.4 RenderExposure 1 1 diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index 1d8ebdf6fb..05bd89e3f6 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -333,7 +333,7 @@ RenderReflectionProbeLevel 1 2 RenderMirrors 1 0 RenderHeroProbeResolution 1 512 RenderHeroProbeDistance 1 16 -RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeUpdateRate 1 2 RenderHeroProbeConservativeUpdateMultiplier 1 4 RenderCASSharpness 1 0.4 RenderExposure 1 1 @@ -375,7 +375,7 @@ RenderReflectionProbeLevel 1 3 RenderMirrors 1 0 RenderHeroProbeResolution 1 1024 RenderHeroProbeDistance 1 16 -RenderHeroProbeUpdateRate 1 1 +RenderHeroProbeUpdateRate 1 2 RenderHeroProbeConservativeUpdateMultiplier 1 4 RenderCASSharpness 1 0.4 RenderExposure 1 1 diff --git a/indra/newview/fsareasearch.cpp b/indra/newview/fsareasearch.cpp index 4e58c4e28e..ef4efc84fc 100644 --- a/indra/newview/fsareasearch.cpp +++ b/indra/newview/fsareasearch.cpp @@ -156,6 +156,7 @@ FSAreaSearch::FSAreaSearch(const LLSD& key) : mFilterPhantom(false), mFilterAttachment(false), mFilterMoaP(false), + mFilterReflectionProbe(false), mFilterDistance(false), mFilterDistanceMin(0), mFilterDistanceMax(999999), @@ -166,6 +167,7 @@ FSAreaSearch::FSAreaSearch(const LLSD& key) : mBeacons(false), mExcludeAttachment(true), mExcludeTemporary(true), + mExcludeReflectionProbe(false), mExcludePhysics(true), mExcludeChildPrims(true), mExcludeNeighborRegions(true), @@ -545,6 +547,11 @@ bool FSAreaSearch::isSearchableObject(LLViewerObject* objectp, LLViewerRegion* o return false; } + if (mExcludeReflectionProbe && objectp->mReflectionProbe.notNull()) + { + return false; + } + return true; } @@ -908,6 +915,11 @@ void FSAreaSearch::matchObject(FSObjectProperties& details, LLViewerObject* obje return; } + if (mFilterReflectionProbe && !objectp->mReflectionProbe.notNull()) + { + return; + } + //----------------------------------------------------------------------- // Find text //----------------------------------------------------------------------- @@ -2217,6 +2229,10 @@ bool FSPanelAreaSearchFilter::postBuild() mCheckboxExcludetemporary->set(true); mCheckboxExcludetemporary->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); + mCheckboxExcludeReflectionProbes = getChild("exclude_reflection_probes"); + mCheckboxExcludeReflectionProbes->set(false); + mCheckboxExcludeReflectionProbes->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); + mCheckboxExcludeChildPrim = getChild("exclude_childprim"); mCheckboxExcludeChildPrim->set(true); mCheckboxExcludeChildPrim->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); @@ -2240,6 +2256,9 @@ bool FSPanelAreaSearchFilter::postBuild() mCheckboxMoaP = getChild("filter_moap"); mCheckboxMoaP->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); + mCheckboxReflectionProbe = getChild("filter_reflection_probe"); + mCheckboxReflectionProbe->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); + mCheckboxPermCopy = getChild("filter_perm_copy"); mCheckboxPermCopy->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); @@ -2262,6 +2281,7 @@ void FSPanelAreaSearchFilter::onCommitCheckbox() mFSAreaSearch->setFilterForSale(mCheckboxForSale->get()); mFSAreaSearch->setFilterDistance(mCheckboxDistance->get()); mFSAreaSearch->setFilterMoaP(mCheckboxMoaP->get()); + mFSAreaSearch->setFilterReflectionProbe(mCheckboxReflectionProbe->get()); if (mCheckboxExcludePhysics->get()) { @@ -2291,6 +2311,19 @@ void FSPanelAreaSearchFilter::onCommitCheckbox() } mFSAreaSearch->setFilterTemporary(mCheckboxTemporary->get()); + if (mCheckboxExcludeReflectionProbes->get()) + { + mFSAreaSearch->setFilterReflectionProbe(false); + mCheckboxReflectionProbe->set(false); + mCheckboxReflectionProbe->setEnabled(false); + mFSAreaSearch->setExcludeReflectionProbe(true); + } + else + { + mCheckboxReflectionProbe->setEnabled(true); + mFSAreaSearch->setExcludeReflectionProbe(false); + } + if (mCheckboxExcludeAttachment->get()) { mFSAreaSearch->setFilterAttachment(false); diff --git a/indra/newview/fsareasearch.h b/indra/newview/fsareasearch.h index 78d40454dc..a4bb89c2b0 100644 --- a/indra/newview/fsareasearch.h +++ b/indra/newview/fsareasearch.h @@ -141,12 +141,14 @@ public: void setFilterPhantom(bool b) { mFilterPhantom = b; } void setFilterAttachment(bool b) { mFilterAttachment = b; } void setFilterMoaP(bool b) { mFilterMoaP = b; } + void setFilterReflectionProbe(bool b) { mFilterReflectionProbe = b; } void setRegexSearch(bool b) { mRegexSearch = b; } void setBeacons(bool b) { mBeacons = b; } void setExcludeAttachment(bool b) { mExcludeAttachment = b; } void setExcludetemporary(bool b) { mExcludeTemporary = b; } + void setExcludeReflectionProbe(bool b) { mExcludeReflectionProbe = b; } void setExcludePhysics(bool b) { mExcludePhysics = b; } void setExcludeChildPrims(bool b) { mExcludeChildPrims = b; } void setExcludeNeighborRegions(bool b) { mExcludeNeighborRegions = b; } @@ -230,6 +232,7 @@ private: bool mExcludeAttachment; bool mExcludeTemporary; + bool mExcludeReflectionProbe; bool mExcludePhysics; bool mExcludeChildPrims; bool mExcludeNeighborRegions; @@ -240,6 +243,7 @@ private: bool mFilterPhantom; bool mFilterAttachment; bool mFilterMoaP; + bool mFilterReflectionProbe; bool mFilterForSale; S32 mFilterForSaleMin; @@ -382,6 +386,7 @@ private: LLCheckBoxCtrl* mCheckboxLocked; LLCheckBoxCtrl* mCheckboxPhantom; LLCheckBoxCtrl* mCheckboxMoaP; + LLCheckBoxCtrl* mCheckboxReflectionProbe; LLCheckBoxCtrl* mCheckboxDistance; LLSpinCtrl* mSpinDistanceMinValue; LLSpinCtrl* mSpinDistanceMaxValue; @@ -393,6 +398,7 @@ private: LLCheckBoxCtrl* mCheckboxExcludeAttachment; LLCheckBoxCtrl* mCheckboxExcludePhysics; LLCheckBoxCtrl* mCheckboxExcludetemporary; + LLCheckBoxCtrl* mCheckboxExcludeReflectionProbes; LLCheckBoxCtrl* mCheckboxExcludeChildPrim; LLCheckBoxCtrl* mCheckboxExcludeNeighborRegions; LLCheckBoxCtrl* mCheckboxPermCopy; diff --git a/indra/newview/fsfloaterim.cpp b/indra/newview/fsfloaterim.cpp index 136a626252..823552eb10 100644 --- a/indra/newview/fsfloaterim.cpp +++ b/indra/newview/fsfloaterim.cpp @@ -479,6 +479,10 @@ void FSFloaterIM::sendMsgFromInputEditor(EChatType type) { str_version_tag = "Release"; } + else if( viewer_maturity == LLVersionInfo::FSViewerMaturity::STREAMING_VIEWER ) + { + str_version_tag = "Streaming"; + } else if( viewer_maturity == LLVersionInfo::FSViewerMaturity::UNOFFICIAL_VIEWER ) { str_version_tag = "Unofficial"; @@ -502,6 +506,10 @@ void FSFloaterIM::sendMsgFromInputEditor(EChatType type) { str_version_tag = "Unofficial"; } + if( viewer_maturity == LLVersionInfo::FSViewerMaturity::STREAMING_VIEWER ) + { + str_version_tag = "Streaming"; + } else if( viewer_maturity != LLVersionInfo::FSViewerMaturity::RELEASE_VIEWER ) { str_version_tag = "pre-Release"; @@ -1245,6 +1253,22 @@ FSFloaterIM* FSFloaterIM::show(const LLUUID& session_id) if (!gIMMgr->hasSession(session_id)) return nullptr; + // [FIRE-34494] fixes unable to open an IM with someone who started a group chat + // Prevent showing non-IM sessions in FSFloaterIM::show() + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if (!session || ( + IM_NOTHING_SPECIAL != session->mType + && IM_SESSION_P2P_INVITE != session->mType + && IM_SESSION_INVITE != session->mType + && IM_SESSION_CONFERENCE_START != session->mType + && IM_SESSION_GROUP_START != session->mType)) + { + LL_WARNS("IMVIEW") << "Attempted to show FSFloaterIM for non-IM session: " + << (session ? std::to_string(session->mType) : "null") << LL_ENDL; + return nullptr; + } + // + if (!isChatMultiTab()) { //hide all diff --git a/indra/newview/fsfloaterposer.cpp b/indra/newview/fsfloaterposer.cpp index 5a5f04c7e6..22ac6d0a94 100644 --- a/indra/newview/fsfloaterposer.cpp +++ b/indra/newview/fsfloaterposer.cpp @@ -33,6 +33,7 @@ #include "llcheckboxctrl.h" #include "llcommonutils.h" #include "llcontrolavatar.h" +#include "llnotificationsutil.h" #include "lldiriterator.h" #include "llsdserialize.h" #include "llscrolllistctrl.h" @@ -61,7 +62,10 @@ constexpr std::string_view POSER_TRACKPAD_SENSITIVITY_SAVE_KEY = "FSPoserTrackpa constexpr std::string_view POSER_STOPPOSINGWHENCLOSED_SAVE_KEY = "FSPoserStopPosingWhenClosed"; constexpr std::string_view POSER_RESETBASEROTONEDIT_SAVE_KEY = "FSPoserResetBaseRotationOnEdit"; constexpr std::string_view POSER_SAVEEXTERNALFORMAT_SAVE_KEY = "FSPoserSaveExternalFileAlso"; -constexpr std::string_view POSER_SAVECONFIRMREQUIRED_SAVE_KEY = "FSPoserOnSaveConfirmOverwrite"; +constexpr std::string_view POSER_SAVECONFIRMREQUIRED_SAVE_KEY = "FSPoserOnSaveConfirmOverwrite"; +constexpr char ICON_SAVE_OK[] = "icon_rotation_is_own_work"; +constexpr char ICON_SAVE_FAILED[] = "icon_save_failed_button"; + } // namespace /// @@ -368,19 +372,8 @@ void FSFloaterPoser::onPoseFileSelect() mLoadPosesBtn->setLabel(getString("LoadPoseLabel")); } -void FSFloaterPoser::onClickPoseSave() +void FSFloaterPoser::doPoseSave(LLVOAvatar* avatar, const std::string& filename) { - std::string filename = mPoseSaveNameEditor->getValue().asString(); - if (filename.empty() && hasString("icon_save_failed_button")) - { - mSavePosesBtn->setImageOverlay(getString("icon_save_failed_button"), mSavePosesBtn->getImageOverlayHAlign()); - return; - } - - if (confirmFileOverwrite(filename)) - return; - - LLVOAvatar* avatar = getUiSelectedAvatar(); if (!avatar) return; @@ -393,43 +386,60 @@ void FSFloaterPoser::onClickPoseSave() if (getSavingToBvh()) savePoseToBvh(avatar, filename); - if (hasString("icon_rotation_is_own_work")) - mSavePosesBtn->setImageOverlay(getString("icon_rotation_is_own_work"), mSavePosesBtn->getImageOverlayHAlign()); + if (hasString(ICON_SAVE_OK)) + mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_OK), mSavePosesBtn->getImageOverlayHAlign()); setSavePosesButtonText(!mPoserAnimator.allBaseRotationsAreZero(avatar)); } else { - if (hasString("icon_save_failed_button")) - mSavePosesBtn->setImageOverlay(getString("icon_save_failed_button"), mSavePosesBtn->getImageOverlayHAlign()); - } + if (hasString(ICON_SAVE_FAILED)) + mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign()); + } } -bool FSFloaterPoser::confirmFileOverwrite(std::string fileName) +void FSFloaterPoser::onClickPoseSave() { - if (fileName.empty()) - return false; + std::string filename = mPoseSaveNameEditor->getValue().asString(); + if (filename.empty() && hasString(ICON_SAVE_FAILED)) + { + mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign()); + return; + } + + LLVOAvatar* avatar = getUiSelectedAvatar(); + if (!avatar) + return; + + // if prompts are disabled or file doesn't exist, do the save immediately: + const bool prompt = gSavedSettings.getBOOL(POSER_SAVECONFIRMREQUIRED_SAVE_KEY); - if (!gSavedSettings.getBOOL(POSER_SAVECONFIRMREQUIRED_SAVE_KEY)) - return false; + std::string fullPath = gDirUtilp->getExpandedFilename( + LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, filename + POSE_INTERNAL_FORMAT_FILE_EXT); + const bool exists = gDirUtilp->fileExists(fullPath); - if (!hasString("icon_save_query")) - return false; - - if (mSavePosesBtn->getImageOverlay().notNull() && mSavePosesBtn->getImageOverlay()->getName() == getString("icon_save_query")) - return false; - - std::string fullSavePath = - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, fileName + POSE_INTERNAL_FORMAT_FILE_EXT); - - if (!gDirUtilp->fileExists(fullSavePath)) - return false; - - mSavePosesBtn->setImageOverlay(getString("icon_save_query"), mSavePosesBtn->getImageOverlayHAlign()); - if (hasString("OverWriteLabel")) - mSavePosesBtn->setLabel(getString("OverWriteLabel")); - - return true; + if (!prompt || !exists) + { + // new file or no overwrite guard + doPoseSave(avatar, filename); + } + else + { + // show a modal dialog, passing the pose name along + LLSD args; + args["POSE_NAME"] = filename; + + LLNotificationsUtil::add("ConfirmPoserOverwrite", args, LLSD(), // no payload + [this, avatar, filename](const LLSD& notification, const LLSD& response) + { + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + // user clicked “Yes” + doPoseSave(avatar, filename); + } + // else do nothing (cancel) + }); + } } void FSFloaterPoser::onMouseLeaveSavePoseBtn() @@ -1645,13 +1655,14 @@ std::vector FSFloaterPoser::getUiSelectedPoserJo return joints; } -void FSFloaterPoser::updateManipWithFirstSelectedJoint(std::vector joints) +void FSFloaterPoser::updateManipWithFirstSelectedJoint(std::vector joints) const { - if (!gAgentAvatarp || gAgentAvatarp.isNull()) + auto avatarp = getUiSelectedAvatar(); + if (!avatarp) return; if (joints.size() >= 1) - FSToolCompPose::getInstance()->setJoint(gAgentAvatarp->getJoint(JointKey::construct(joints[0]->jointName()))); + FSToolCompPose::getInstance()->setJoint(avatarp->getJoint(joints[0]->jointName())); else FSToolCompPose::getInstance()->setJoint(nullptr); } diff --git a/indra/newview/fsfloaterposer.h b/indra/newview/fsfloaterposer.h index 622577b0de..7e0e6c42e4 100644 --- a/indra/newview/fsfloaterposer.h +++ b/indra/newview/fsfloaterposer.h @@ -86,6 +86,8 @@ public: void redo() override { onRedoLastChange(); }; bool canRedo() const override { return true; } private: + // Helper function to encapsualte save logic + void doPoseSave(LLVOAvatar* avatar, const std::string& filename); bool postBuild() override; void onOpen(const LLSD& key) override; void onClose(bool app_quitting) override; @@ -136,7 +138,7 @@ public: /// Updates the visual with the first selected joint from the supplied collection, if any. /// /// The collection of selected joints. - static void updateManipWithFirstSelectedJoint(std::vector joints); + void updateManipWithFirstSelectedJoint(std::vector joints) const; /// /// Gets a detectable avatar by its UUID. diff --git a/indra/newview/fsfloaterprimfeed.cpp b/indra/newview/fsfloaterprimfeed.cpp new file mode 100644 index 0000000000..c665d09198 --- /dev/null +++ b/indra/newview/fsfloaterprimfeed.cpp @@ -0,0 +1,912 @@ +/** + * @file fsfloaterprimfeed.cpp + * @brief Implementation of primfeed floater + * @author beq@firestorm + * + * $LicenseInfo:firstyear=2025&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2025, Beq Janus + * + * 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 + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "fsfloaterprimfeed.h" +#include "fsprimfeedconnect.h" +#include "llagent.h" +#include "llagentui.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfloaterreg.h" +#include "lliconctrl.h" +#include "llimagefiltersmanager.h" +#include "llresmgr.h" // LLLocale +#include "llsdserialize.h" +#include "llloadingindicator.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llfloatersnapshot.h" +#include "llsnapshotlivepreview.h" +#include "llfloaterbigpreview.h" +#include "llviewerregion.h" +#include "llviewercontrol.h" +#include "llviewermedia.h" +#include "lltabcontainer.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include +#include "llspinctrl.h" + +#include "llviewernetwork.h" +#include "llnotificationsutil.h" +#include "fsprimfeedauth.h" +#include "llviewernetwork.h" + +static LLPanelInjector t_panel_photo("fsprimfeedphotopanel"); +static LLPanelInjector t_panel_account("fsprimfeedaccountpanel"); + +/////////////////////////// +// FSPrimfeedPhotoPanel///// +/////////////////////////// + +FSPrimfeedPhotoPanel::FSPrimfeedPhotoPanel() : + mResolutionComboBox(nullptr), + mRefreshBtn(nullptr), + mWorkingLabel(nullptr), + mThumbnailPlaceholder(nullptr), + mDescriptionTextBox(nullptr), + mLocationCheckbox(nullptr), + mRatingComboBox(nullptr), + mPostButton(nullptr), + mBtnPreview(nullptr), + mBigPreviewFloater(nullptr) +{ + mCommitCallbackRegistrar.add("SocialSharing.SendPhoto", [this](LLUICtrl*, const LLSD&) { onSend(); }); + mCommitCallbackRegistrar.add("SocialSharing.RefreshPhoto", [this](LLUICtrl*, const LLSD&) { onClickNewSnapshot(); }); + mCommitCallbackRegistrar.add("SocialSharing.BigPreview", [this](LLUICtrl*, const LLSD&) { onClickBigPreview(); }); + mCommitCallbackRegistrar.add("Primfeed.Info", + [](LLUICtrl*, const LLSD& param) + { + const std::string url = param.asString(); + LL_DEBUGS("primfeed") << "Info button clicked, opening " << url << LL_ENDL; + LLWeb::loadURLExternal(url); + }); +} + +FSPrimfeedPhotoPanel::~FSPrimfeedPhotoPanel() +{ + if (mPreviewHandle.get()) + { + mPreviewHandle.get()->die(); + } + + FSPrimfeedAuth::sPrimfeedAuthPump->stopListening("FSPrimfeedAccountPanel"); + + gSavedSettings.setS32("FSLastSnapshotToPrimfeedResolution", getChild("resolution_combobox")->getCurrentIndex()); + gSavedSettings.setS32("FSLastSnapshotToPrimfeedWidth", getChild("custom_snapshot_width")->getValue().asInteger()); + gSavedSettings.setS32("FSLastSnapshotToPrimfeedHeight", getChild("custom_snapshot_height")->getValue().asInteger()); +} + +bool FSPrimfeedPhotoPanel::postBuild() +{ + setVisibleCallback([this](LLUICtrl*, bool visible) { onVisibilityChange(visible); }); + + mResolutionComboBox = getChild("resolution_combobox"); + mResolutionComboBox->setCommitCallback([this](LLUICtrl*, const LLSD&) { updateResolution(true); }); + mFilterComboBox = getChild("filters_combobox"); + mFilterComboBox->setCommitCallback([this](LLUICtrl*, const LLSD&) { updateResolution(true); }); + mRefreshBtn = getChild("new_snapshot_btn"); + mBtnPreview = getChild("big_preview_btn"); + mWorkingLabel = getChild("working_lbl"); + mThumbnailPlaceholder = getChild("thumbnail_placeholder"); + mDescriptionTextBox = getChild("photo_description"); + mLocationCheckbox = getChild("add_location_cb"); + mCommercialCheckbox = getChild("primfeed_commercial_content"); + mPublicGalleryCheckbox = getChild("primfeed_add_to_public_gallery"); + mRatingComboBox = getChild("rating_combobox"); + mPostButton = getChild("post_photo_btn"); + mCancelButton = getChild("cancel_photo_btn"); + mBigPreviewFloater = dynamic_cast(LLFloaterReg::getInstance("big_preview")); + + // Update custom resolution controls with lambdas + getChild("custom_snapshot_width")->setCommitCallback([this](LLUICtrl*, const LLSD&) { updateResolution(true); }); + getChild("custom_snapshot_height")->setCommitCallback([this](LLUICtrl*, const LLSD&) { updateResolution(true); }); + getChild("keep_aspect_ratio")->setCommitCallback([this](LLUICtrl*, const LLSD&) { updateResolution(true); }); + + getChild("resolution_combobox")->setCurrentByIndex(gSavedSettings.getS32("FSLastSnapshotToPrimfeedResolution")); + getChild("custom_snapshot_width")->setValue(gSavedSettings.getS32("FSLastSnapshotToPrimfeedWidth")); + getChild("custom_snapshot_height")->setValue(gSavedSettings.getS32("FSLastSnapshotToPrimfeedHeight")); + + // Update filter list + std::vector filter_list = LLImageFiltersManager::getInstance()->getFiltersList(); + auto* filterbox = static_cast(mFilterComboBox); + for (const std::string& filter : filter_list) + { + filterbox->add(filter); + } + + return LLPanel::postBuild(); +} + +// static +void FSFloaterPrimfeed::update() +{ + if (LLFloaterReg::instanceVisible("primfeed")) + { + LLFloaterSnapshotBase::ImplBase::updatePreviewList(true, true); + } +} + +// virtual +S32 FSPrimfeedPhotoPanel::notify(const LLSD& info) +{ + if (info.has("snapshot-updating")) + { + // Disable the Post button and whatever else while the snapshot is not updated + // updateControls(); + return 1; + } + + if (info.has("snapshot-updated")) + { + // Enable the send/post/save buttons. + updateControls(); + + // The refresh button is initially hidden. We show it after the first update, + // i.e. after snapshot is taken + + if (LLUICtrl* refresh_button = getRefreshBtn(); !refresh_button->getVisible()) + { + refresh_button->setVisible(true); + } + return 1; + } + + return 0; +} + +void FSPrimfeedPhotoPanel::draw() +{ + auto previewp = static_cast(mPreviewHandle.get()); + + // Enable interaction only if no transaction with the service is on-going (prevent duplicated posts) + auto can_post = !(FSPrimfeedConnect::instance().isTransactionOngoing()) && FSPrimfeedAuth::isAuthorized(); + + mCancelButton->setEnabled(can_post); + mDescriptionTextBox->setEnabled(can_post); + mRatingComboBox->setEnabled(can_post); + mResolutionComboBox->setEnabled(can_post); + mFilterComboBox->setEnabled(can_post); + mRefreshBtn->setEnabled(can_post); + mBtnPreview->setEnabled(can_post); + mLocationCheckbox->setEnabled(can_post); + mPublicGalleryCheckbox->setEnabled(can_post); + mCommercialCheckbox->setEnabled(can_post); + + // Reassign the preview floater if we have the focus and the preview exists + if (hasFocus() && isPreviewVisible()) + { + attachPreview(); + } + + // Toggle the button state as appropriate + bool preview_active = (isPreviewVisible() && mBigPreviewFloater->isFloaterOwner(getParentByType())); + mBtnPreview->setToggleState(preview_active); + + // Display the preview if one is available + if (previewp && previewp->getThumbnailImage()) + { + const LLRect& thumbnail_rect = mThumbnailPlaceholder->getRect(); + const S32 thumbnail_w = previewp->getThumbnailWidth(); + const S32 thumbnail_h = previewp->getThumbnailHeight(); + + // calc preview offset within the preview rect + const S32 local_offset_x = (thumbnail_rect.getWidth() - thumbnail_w) / 2; + const S32 local_offset_y = (thumbnail_rect.getHeight() - thumbnail_h) / 2; + S32 offset_x = thumbnail_rect.mLeft + local_offset_x; + S32 offset_y = thumbnail_rect.mBottom + local_offset_y; + + gGL.matrixMode(LLRender::MM_MODELVIEW); + // Apply floater transparency to the texture unless the floater is focused. + F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency(); + LLColor4 color = LLColor4::white; + gl_draw_scaled_image(offset_x, offset_y, thumbnail_w, thumbnail_h, previewp->getThumbnailImage(), color % alpha); + } + + // Update the visibility of the working (computing preview) label + mWorkingLabel->setVisible(!(previewp && previewp->getSnapshotUpToDate())); + + // Enable Post if we have a preview to send and no on going connection being processed + mPostButton->setEnabled(can_post && (previewp && previewp->getSnapshotUpToDate())); + + // Draw the rest of the panel on top of it + LLPanel::draw(); +} + +LLSnapshotLivePreview* FSPrimfeedPhotoPanel::getPreviewView() +{ + auto previewp = (LLSnapshotLivePreview*)mPreviewHandle.get(); + return previewp; +} + +void FSPrimfeedPhotoPanel::onVisibilityChange(bool visible) +{ + if (visible) + { + if (mPreviewHandle.get()) + { + LLSnapshotLivePreview* preview = getPreviewView(); + if (preview) + { + LL_DEBUGS() << "opened, updating snapshot" << LL_ENDL; + preview->updateSnapshot(true); + } + } + else + { + LLRect full_screen_rect = getRootView()->getRect(); + LLSnapshotLivePreview::Params p; + p.rect(full_screen_rect); + auto previewp = new LLSnapshotLivePreview(p); + mPreviewHandle = previewp->getHandle(); + + previewp->setContainer(this); + previewp->setSnapshotType(LLSnapshotModel::SNAPSHOT_WEB); + previewp->setSnapshotFormat(LLSnapshotModel::SNAPSHOT_FORMAT_PNG); + previewp->setThumbnailSubsampled(true); // We want the preview to reflect the *saved* image + previewp->setAllowRenderUI(false); // We do not want the rendered UI in our snapshots + previewp->setAllowFullScreenPreview(false); // No full screen preview in SL Share mode + previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect()); + + updateControls(); + } + } +} + +void FSPrimfeedPhotoPanel::onClickNewSnapshot() +{ + LLSnapshotLivePreview* previewp = getPreviewView(); + if (previewp) + { + previewp->updateSnapshot(true); + } +} + +void FSPrimfeedPhotoPanel::onClickBigPreview() +{ + // Toggle the preview + if (isPreviewVisible()) + { + LLFloaterReg::hideInstance("big_preview"); + } + else + { + attachPreview(); + LLFloaterReg::showInstance("big_preview"); + } +} + +bool FSPrimfeedPhotoPanel::isPreviewVisible() const +{ + return (mBigPreviewFloater && mBigPreviewFloater->getVisible()); +} + +void FSPrimfeedPhotoPanel::attachPreview() +{ + if (mBigPreviewFloater) + { + LLSnapshotLivePreview* previewp = getPreviewView(); + mBigPreviewFloater->setPreview(previewp); + mBigPreviewFloater->setFloaterOwner(getParentByType()); + } +} + +void FSPrimfeedPhotoPanel::onSend() +{ + sendPhoto(); +} + +bool FSPrimfeedPhotoPanel::onPrimfeedConnectStateChange(const LLSD& /*data*/) +{ + if (FSPrimfeedAuth::isAuthorized()) + { + sendPhoto(); + } + + return false; +} + +void FSPrimfeedPhotoPanel::sendPhoto() +{ + auto ratingToString = [&](int rating) + { + static const std::array RATING_NAMES = { + "general", // 1 + "moderate", // 2 + "adult", // 3 + "adult_plus" // 4 + }; + + // clamp into [1,4] + int idx = llclamp(rating, 1, 4) - 1; + return RATING_NAMES[idx]; + }; + // Get the description (primfeed has no title/tags etc at this point) + std::string description = mDescriptionTextBox->getValue().asString(); + + // Get the content rating + int content_rating = mRatingComboBox->getValue().asInteger(); + bool post_to_public_gallery = mPublicGalleryCheckbox->getValue().asBoolean(); + bool commercial_content = mCommercialCheckbox->getValue().asBoolean(); + + // Get the image + LLSnapshotLivePreview* previewp = getPreviewView(); + + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_POSTING); + LLSD params; + params["rating"] = ratingToString(content_rating); + params["content"] = description; + params["is_commercial"] = commercial_content; + params["post_to_public_gallery"] = post_to_public_gallery; + // Add the location if required + + if (bool add_location = mLocationCheckbox->getValue().asBoolean(); add_location) + { + // Get the SLURL for the location + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + std::string slurl_string = slurl.getSLURLString(); + + params["location"] = slurl_string; + } + + FSPrimfeedConnect::instance().uploadPhoto(params, previewp->getFormattedImage().get(), + [this](bool success, const std::string& url) + { + if (success) + { + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_POSTED); + static LLCachedControl open_url_on_post(gSavedPerAccountSettings, + "FSPrimfeedOpenURLOnPost", true); + if (open_url_on_post) + { + LLWeb::loadURLExternal(url); + } + LLSD args; + args["PF_POSTURL"] = url; + LLNotificationsUtil::add("FSPrimfeedUploadComplete", args); + } + else + { + mWorkingLabel->setValue("Error posting to Primfeed"); + mPostButton->setEnabled(true); + } + }); + updateControls(); +} + +void FSPrimfeedPhotoPanel::clearAndClose() +{ + mDescriptionTextBox->setValue(""); + + if (LLFloater* floater = getParentByType()) + { + floater->closeFloater(); + if (mBigPreviewFloater) + { + mBigPreviewFloater->closeOnFloaterOwnerClosing(floater); + } + } +} + +void FSPrimfeedPhotoPanel::updateControls() +{ + // LLSnapshotLivePreview* previewp = getPreviewView(); + updateResolution(false); +} + +void FSPrimfeedPhotoPanel::updateResolution(bool do_update) +{ + auto combobox = static_cast(mResolutionComboBox); + auto filterbox = static_cast(mFilterComboBox); + + std::string sdstring = combobox->getSelectedValue(); + LLSD sdres; + std::stringstream sstream(sdstring); + LLSDSerialize::fromNotation(sdres, sstream, sdstring.size()); + + S32 width = sdres[0]; + S32 height = sdres[1]; + + // Note : index 0 of the filter drop down is assumed to be "No filter" in whichever locale + std::string filter_name = (filterbox->getCurrentIndex() ? filterbox->getSimple() : ""); + + if (auto previewp = static_cast(mPreviewHandle.get()); previewp && combobox->getCurrentIndex() >= 0) + { + checkAspectRatio(width); + + S32 original_width = 0; + S32 original_height = 0; + previewp->getSize(original_width, original_height); + + if (width == 0 || height == 0) + { + // take resolution from current window size + LL_DEBUGS() << "Setting preview res from window: " << gViewerWindow->getWindowWidthRaw() << "x" + << gViewerWindow->getWindowHeightRaw() << LL_ENDL; + previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); + } + else if (width == -1 || height == -1) + { + // take resolution from custom size + LLSpinCtrl* width_spinner = getChild("custom_snapshot_width"); + LLSpinCtrl* height_spinner = getChild("custom_snapshot_height"); + S32 custom_width = width_spinner->getValue().asInteger(); + S32 custom_height = height_spinner->getValue().asInteger(); + if (checkImageSize(previewp, custom_width, custom_height, true, previewp->getMaxImageSize())) + { + width_spinner->set((F32)custom_width); + height_spinner->set((F32)custom_height); + } + LL_DEBUGS() << "Setting preview res from custom: " << custom_width << "x" << custom_height << LL_ENDL; + previewp->setSize(custom_width, custom_height); + } + else + { + // use the resolution from the selected pre-canned drop-down choice + LL_DEBUGS() << "Setting preview res selected from combo: " << width << "x" << height << LL_ENDL; + previewp->setSize(width, height); + } + + previewp->getSize(width, height); + if ((original_width != width) || (original_height != height)) + { + previewp->setSize(width, height); + if (do_update) + { + previewp->updateSnapshot(true, true); + updateControls(); + } + } + // Get the old filter, compare to the current one "filter_name" and set if changed + std::string original_filter = previewp->getFilter(); + if (original_filter != filter_name) + { + previewp->setFilter(filter_name); + if (do_update) + { + previewp->updateSnapshot(false, true); + updateControls(); + } + } + } + + bool custom_resolution = static_cast(mResolutionComboBox)->getSelectedValue().asString() == "[i-1,i-1]"; + getChild("custom_snapshot_width")->setEnabled(custom_resolution); + getChild("custom_snapshot_height")->setEnabled(custom_resolution); + getChild("keep_aspect_ratio")->setEnabled(custom_resolution); +} + +void FSPrimfeedPhotoPanel::checkAspectRatio(S32 index) +{ + LLSnapshotLivePreview* previewp = getPreviewView(); + + bool keep_aspect = false; + + if (0 == index) // current window size + { + keep_aspect = true; + } + else if (-1 == index) + { + keep_aspect = getChild("keep_aspect_ratio")->get(); + } + else // predefined resolution + { + keep_aspect = false; + } + + if (previewp) + { + previewp->mKeepAspectRatio = keep_aspect; + } +} + +LLUICtrl* FSPrimfeedPhotoPanel::getRefreshBtn() +{ + return mRefreshBtn; +} + +void FSPrimfeedPhotoPanel::onOpen(const LLSD& key) +{ + if (!FSPrimfeedAuth::isAuthorized()) + { + // Reauthorise if necessary. + FSPrimfeedAuth::initiateAuthRequest(); + LLSD dummy; + onPrimfeedConnectStateChange(dummy); + } +} + +void FSPrimfeedPhotoPanel::uploadCallback(bool success, const LLSD& response) +{ + LLSD args; + if (success && response["stat"].asString() == "ok") + { + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_POSTED); + args["PF_POSTURL"] = response["postUrl"]; + LLNotificationsUtil::add("FSPrimfeedUploadComplete", args); + } + else + { + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_POST_FAILED); + } +} + +void FSPrimfeedPhotoPanel::primfeedAuthResponse(bool success, const LLSD& response) +{ + if (!success) + { + if (response.has("status") && response["status"].asString() == "reset") + { + LL_INFOS("Primfeed") << "Primfeed authorization has been reset." << LL_ENDL; + } + else + { + // Complain about failed auth here. + LL_WARNS("Primfeed") << "Primfeed authentication failed." << LL_ENDL; + } + } + onPrimfeedConnectStateChange(response); +} + +bool FSPrimfeedPhotoPanel::checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, bool isWidthChanged, S32 max_value) +{ + S32 w = width; + S32 h = height; + + if (previewp && previewp->mKeepAspectRatio) + { + if (gViewerWindow->getWindowWidthRaw() < 1 || gViewerWindow->getWindowHeightRaw() < 1) + { + return false; + } + + // aspect ratio of the current window + F32 aspect_ratio = static_cast(gViewerWindow->getWindowWidthRaw()) / static_cast(gViewerWindow->getWindowHeightRaw()); + + // change another value proportionally + if (isWidthChanged) + { + height = ll_round(static_cast(width) / aspect_ratio); + } + else + { + width = ll_round(static_cast(height) * aspect_ratio); + } + + // bound w/h by the max_value + if (width > max_value || height > max_value) + { + if (width > height) + { + width = max_value; + height = ll_round(static_cast(width) / aspect_ratio); + } + else + { + height = max_value; + width = ll_round(static_cast(height) * aspect_ratio); + } + } + } + + return (w != width || h != height); +} + +/////////////////////////// +// FSPrimfeedAccountPanel/// +/////////////////////////// + +FSPrimfeedAccountPanel::FSPrimfeedAccountPanel() : + mAccountConnectedAsLabel(nullptr), + mAccountNameLink(nullptr), + mAccountPlan(nullptr), + mPanelButtons(nullptr), + mConnectButton(nullptr), + mDisconnectButton(nullptr) +{ + mCommitCallbackRegistrar.add("SocialSharing.Connect", [this](LLUICtrl*, const LLSD&) { onConnect(); }); + mCommitCallbackRegistrar.add("SocialSharing.Disconnect", [this](LLUICtrl*, const LLSD&) { onDisconnect(); }); + + FSPrimfeedAuth::sPrimfeedAuthPump->listen("FSPrimfeedAccountPanel", + [this](const LLSD& data) + { + bool success = data["success"].asBoolean(); + primfeedAuthResponse(success, data); + return true; + }); + + setVisibleCallback([this](LLUICtrl*, bool visible) { onVisibilityChange(visible); }); +} + +bool FSPrimfeedAccountPanel::postBuild() +{ + mAccountConnectedAsLabel = getChild("connected_as_label"); + mAccountNameLink = getChild("primfeed_account_name"); + mAccountPlan = getChild("primfeed_account_plan"); + mPanelButtons = getChild("panel_buttons"); + mConnectButton = getChild("connect_btn"); + mDisconnectButton = getChild("disconnect_btn"); + + LLSD dummy; + onPrimfeedConnectStateChange(dummy); + return LLPanel::postBuild(); +} + +void FSPrimfeedAccountPanel::draw() +{ + FSPrimfeedConnect::EConnectionState connection_state = FSPrimfeedConnect::instance().getConnectionState(); + static FSPrimfeedConnect::EConnectionState last_state = FSPrimfeedConnect::PRIMFEED_DISCONNECTED; + + // Update the connection state if it has changed + if (connection_state != last_state) + { + onPrimfeedConnectStateChange(LLSD()); + last_state = connection_state; + } + + LLPanel::draw(); +} + +void FSPrimfeedAccountPanel::primfeedAuthResponse(bool success, const LLSD& response) +{ + if (!success) + { + LL_WARNS("Primfeed") << "Primfeed authentication failed." << LL_ENDL; + LLWeb::loadURLExternal("https://www.primfeed.com/login"); + } + onPrimfeedConnectStateChange(response); +} + +void FSPrimfeedAccountPanel::onVisibilityChange(bool visible) +{ + if (visible) + { + // Connected + if (FSPrimfeedAuth::isAuthorized()) + { + showConnectedLayout(); + } + else + { + showDisconnectedLayout(); + } + } +} + +bool FSPrimfeedAccountPanel::onPrimfeedConnectStateChange(const LLSD&) +{ + if (FSPrimfeedAuth::isAuthorized() || FSPrimfeedConnect::instance().getConnectionState() == FSPrimfeedConnect::PRIMFEED_CONNECTING) + { + showConnectedLayout(); + } + else + { + showDisconnectedLayout(); + } + onPrimfeedConnectInfoChange(); + return false; +} + +bool FSPrimfeedAccountPanel::onPrimfeedConnectInfoChange() +{ + std::string clickable_name{ "" }; + + static LLCachedControl primfeed_username(gSavedPerAccountSettings, "FSPrimfeedUsername"); + static LLCachedControl primfeed_profile_link(gSavedPerAccountSettings, "FSPrimfeedProfileLink"); + static LLCachedControl primfeed_plan(gSavedPerAccountSettings, "FSPrimfeedPlan"); + + // Strings of format [http://www.somewebsite.com Click Me] become clickable text + if (!primfeed_username().empty()) + { + clickable_name = std::string("[") + std::string(primfeed_profile_link) + " " + std::string(primfeed_username) + "]"; + } + + mAccountNameLink->setText(clickable_name); + mAccountPlan->setText(primfeed_plan()); + + return false; +} + +void FSPrimfeedAccountPanel::showConnectButton() +{ + if (!mConnectButton->getVisible()) + { + mConnectButton->setVisible(true); + mDisconnectButton->setVisible(false); + } +} + +void FSPrimfeedAccountPanel::hideConnectButton() +{ + if (mConnectButton->getVisible()) + { + mConnectButton->setVisible(false); + mDisconnectButton->setVisible(true); + } +} + +void FSPrimfeedAccountPanel::showDisconnectedLayout() +{ + mAccountConnectedAsLabel->setText(getString("primfeed_disconnected")); + mAccountNameLink->setText(std::string("")); + mAccountPlan->setText(getString("primfeed_plan_unknown")); + showConnectButton(); +} + +void FSPrimfeedAccountPanel::showConnectedLayout() +{ + mAccountConnectedAsLabel->setText(getString("primfeed_connected")); + hideConnectButton(); +} + +void FSPrimfeedAccountPanel::onConnect() +{ + FSPrimfeedAuth::initiateAuthRequest(); + LLSD dummy; + onPrimfeedConnectStateChange(dummy); +} + +void FSPrimfeedAccountPanel::onDisconnect() +{ + FSPrimfeedAuth::resetAuthStatus(); + LLSD dummy; + onPrimfeedConnectStateChange(dummy); +} + +//////////////////////// +// FSFloaterPrimfeed///// +//////////////////////// + +FSFloaterPrimfeed::FSFloaterPrimfeed(const LLSD& key) : + LLFloater(key), + mPrimfeedPhotoPanel(nullptr), + mStatusErrorText(nullptr), + mStatusLoadingText(nullptr), + mStatusLoadingIndicator(nullptr), + mPrimfeedAccountPanel(nullptr) +{ + mCommitCallbackRegistrar.add("SocialSharing.Cancel", [this](LLUICtrl*, const LLSD&) { onCancel(); }); +} + +void FSFloaterPrimfeed::onClose(bool app_quitting) +{ + if (auto big_preview_floater = LLFloaterReg::getTypedInstance("big_preview")) + { + big_preview_floater->closeOnFloaterOwnerClosing(this); + } + LLFloater::onClose(app_quitting); +} + +void FSFloaterPrimfeed::onCancel() +{ + if (auto big_preview_floater = LLFloaterReg::getTypedInstance("big_preview")) + { + big_preview_floater->closeOnFloaterOwnerClosing(this); + } + closeFloater(); +} + +bool FSFloaterPrimfeed::postBuild() +{ + // Keep tab of the Photo Panel + mPrimfeedPhotoPanel = static_cast(getChild("panel_primfeed_photo")); + mPrimfeedAccountPanel = static_cast(getChild("panel_primfeed_account")); + // Connection status widgets + mStatusErrorText = getChild("connection_error_text"); + mStatusLoadingText = getChild("connection_loading_text"); + mStatusLoadingIndicator = getChild("connection_loading_indicator"); + + return LLFloater::postBuild(); +} + +void FSFloaterPrimfeed::showPhotoPanel() +{ + auto parent = dynamic_cast(mPrimfeedPhotoPanel->getParent()); + if (!parent) + { + LL_WARNS() << "Cannot find panel container" << LL_ENDL; + return; + } + + parent->selectTabPanel(mPrimfeedPhotoPanel); +} + +void FSFloaterPrimfeed::draw() +{ + if (mStatusErrorText && mStatusLoadingText && mStatusLoadingIndicator) + { + mStatusErrorText->setVisible(false); + mStatusLoadingText->setVisible(false); + mStatusLoadingIndicator->setVisible(false); + + FSPrimfeedConnect::EConnectionState connection_state = FSPrimfeedConnect::instance().getConnectionState(); + std::string status_text; + + if (FSPrimfeedAuth::isAuthorized()) + { + switch (connection_state) + { + case FSPrimfeedConnect::PRIMFEED_POSTING: + { + // Posting indicator + mStatusLoadingText->setVisible(true); + status_text = LLTrans::getString("SocialPrimfeedPosting"); + mStatusLoadingText->setValue(status_text); + mStatusLoadingIndicator->setVisible(true); + break; + } + case FSPrimfeedConnect::PRIMFEED_POST_FAILED: + { + // Error posting to the service + mStatusErrorText->setVisible(true); + status_text = LLTrans::getString("SocialPrimfeedErrorPosting"); + mStatusErrorText->setValue(status_text); + break; + } + default: + { + // LL_WARNS("Prmfeed") << "unexpected state" << connection_state << LL_ENDL; + break; + } + } + } + else if (FSPrimfeedAuth::isPendingAuth()) + { + // Show the status text when authorisation is pending + mStatusLoadingText->setVisible(true); + status_text = LLTrans::getString("SocialPrimfeedConnecting"); + mStatusLoadingText->setValue(status_text); + } + else + { + // Show the status text when not authorised + mStatusErrorText->setVisible(true); + status_text = LLTrans::getString("SocialPrimfeedNotAuthorized"); + mStatusErrorText->setValue(status_text); + } + } + LLFloater::draw(); +} + +void FSFloaterPrimfeed::onOpen(const LLSD& key) +{ + mPrimfeedPhotoPanel->onOpen(key); +} + +LLSnapshotLivePreview* FSFloaterPrimfeed::getPreviewView() +{ + if (mPrimfeedPhotoPanel) + { + return mPrimfeedPhotoPanel->getPreviewView(); + } + return nullptr; +} diff --git a/indra/newview/fsfloaterprimfeed.h b/indra/newview/fsfloaterprimfeed.h new file mode 100644 index 0000000000..312f06c130 --- /dev/null +++ b/indra/newview/fsfloaterprimfeed.h @@ -0,0 +1,154 @@ +/** +* @file fsfloaterprimfeed.cpp +* @brief Declaration of primfeed floater +* @author beq@firestorm +* + * $LicenseInfo:firstyear=2025&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2025, Beq Janus + * + * 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 + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ +*/ +#ifndef FS_FLOATERPRIMFEED_H +#define FS_FLOATERPRIMFEED_H + +#include "llfloater.h" +#include "lltextbox.h" +#include "llviewertexture.h" + +class LLIconCtrl; +class LLCheckBoxCtrl; +class LLSnapshotLivePreview; +class LLFloaterBigPreview; + +/* + * (TODO) Beq: Refactor this with Flickr + * Primfeed floater is copied heavily from the LLFlaoterFlickr class and deliberately implemetns much of the underlying plumbinng into the connector class. + * Once this is bedded in and any initial issues are addressed, it would be sensible to refactor both the flickr and primfeed classes to share a common base. + * In particular a ref counted test for the livepreview would eliminate the need for the static update method in the app mainloop. +*/ +class FSPrimfeedPhotoPanel : public LLPanel +{ +public: + FSPrimfeedPhotoPanel(); + ~FSPrimfeedPhotoPanel(); + + bool postBuild() override; + S32 notify(const LLSD& info); + void draw() override; + + LLSnapshotLivePreview* getPreviewView(); + void onVisibilityChange(bool new_visibility); + void onClickNewSnapshot(); + void onClickBigPreview(); + void onSend(); + bool onPrimfeedConnectStateChange(const LLSD& data); + + void sendPhoto(); + void clearAndClose(); + + void updateControls(); + void updateResolution(bool do_update); + void checkAspectRatio(S32 index); + LLUICtrl* getRefreshBtn(); + + void onOpen(const LLSD& key) override; + void primfeedAuthResponse(bool success, const LLSD& response); + void uploadCallback(bool success, const LLSD& response); + +private: + bool isPreviewVisible() const; + void attachPreview(); + + bool checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, bool isWidthChanged, S32 max_value); + + LLHandle mPreviewHandle; + + LLUICtrl * mResolutionComboBox; + LLUICtrl * mFilterComboBox; + LLUICtrl * mRefreshBtn; + LLUICtrl * mWorkingLabel; + LLUICtrl * mThumbnailPlaceholder; + LLUICtrl * mDescriptionTextBox; + LLUICtrl * mLocationCheckbox; + + LLUICtrl * mCommercialCheckbox; + LLUICtrl * mPublicGalleryCheckbox; + LLUICtrl * mRatingComboBox; + LLUICtrl * mPostButton; + LLUICtrl * mCancelButton; + LLButton * mBtnPreview; + + LLFloaterBigPreview * mBigPreviewFloater; +}; + +class FSPrimfeedAccountPanel : public LLPanel +{ +public: + FSPrimfeedAccountPanel(); + bool postBuild() override; + void draw() override; + +private: + void onVisibilityChange(bool new_visibility); + void primfeedAuthResponse(bool success, const LLSD& response); + bool onPrimfeedConnectStateChange(const LLSD& data); + bool onPrimfeedConnectInfoChange(); + void onConnect(); + void onDisconnect(); + + void showConnectButton(); + void hideConnectButton(); + void showDisconnectedLayout(); + void showConnectedLayout(); + + LLTextBox* mAccountConnectedAsLabel; + LLTextBox* mAccountNameLink; + LLTextBox* mAccountPlan; + LLUICtrl* mPanelButtons; + LLUICtrl* mConnectButton; + LLUICtrl* mDisconnectButton; +}; + + +class FSFloaterPrimfeed : public LLFloater +{ +public: + explicit FSFloaterPrimfeed(const LLSD& key); + static void update(); + bool postBuild() override; + void draw() override; + void onClose(bool app_quitting) override; + void onCancel(); + + void showPhotoPanel(); + + void onOpen(const LLSD& key) override; + LLSnapshotLivePreview* getPreviewView(); + +private: + FSPrimfeedPhotoPanel* mPrimfeedPhotoPanel; + FSPrimfeedAccountPanel* mPrimfeedAccountPanel; + LLTextBox* mStatusErrorText; + LLTextBox* mStatusLoadingText; + LLUICtrl* mStatusLoadingIndicator; +}; + +#endif // LL_FSFLOATERPRIMFEED_H + diff --git a/indra/newview/fspanellogin.cpp b/indra/newview/fspanellogin.cpp index 1c6d7ddf98..595b47dc47 100644 --- a/indra/newview/fspanellogin.cpp +++ b/indra/newview/fspanellogin.cpp @@ -923,6 +923,12 @@ void FSPanelLogin::loadLoginPage() // login page (web) content version params["login_content_version"] = gSavedSettings.getString("LoginContentVersion"); + // No version popup + if (gSavedSettings.getBOOL("FSNoVersionPopup")) + { + params["noversionpopup"] = "true"; + } + // Make an LLURI with this augmented info std::string url = login_page.scheme().empty()? login_page.authority() : login_page.scheme() + "://" + login_page.authority(); LLURI login_uri(LLURI::buildHTTP(url, diff --git a/indra/newview/fsposeranimator.h b/indra/newview/fsposeranimator.h index 8056ba7785..fd67de8770 100644 --- a/indra/newview/fsposeranimator.h +++ b/indra/newview/fsposeranimator.h @@ -190,18 +190,18 @@ public: /// /// An ordered list of poser joints, clustered by body-area. /// Order is based on ease-of-use. - /// Not necessarily exhaustive, just the joints we care to edit without adding UI clutter. /// /// /// For an implementation of something other than LLJoints, different name(s) may be required. + /// A bvhEndSiteValue is only required if the bone has no descendants. /// const std::vector PoserJoints{ // head, torso, legs - { "mHead", "", BODY, { "mEyeLeft", "mEyeRight", "mFaceRoot" }, "0.000 0.076 0.000" }, + { "mHead", "", BODY, { "mEyeLeft", "mEyeRight", "mFaceRoot", "mSkull" }, "0.000 0.076 0.000" }, { "mNeck", "", BODY, { "mHead" }, "0.000 0.251 -0.010" }, - { "mPelvis", "", WHOLEAVATAR, { "mTorso", "mHipLeft", "mHipRight", "mTail1", "mGroin", "mHindLimbsRoot" }, "0.000000 0.000000 0.000000" }, + { "mPelvis", "", WHOLEAVATAR, { "mSpine1", "mHipLeft", "mHipRight", "mTail1", "mGroin", "mHindLimbsRoot" }, "0.000000 0.000000 0.000000" }, { "mChest", "", BODY, { "mNeck", "mCollarLeft", "mCollarRight", "mWingsRoot" }, "0.000 0.205 -0.015" }, - { "mTorso", "", BODY, { "mChest" }, "0.000 0.084 0.000" }, + { "mTorso", "", BODY, { "mSpine3" }, "0.000 0.084 0.000" }, { "mCollarLeft", "mCollarRight", BODY, { "mShoulderLeft" }, "0.085 0.165 -0.021" }, { "mShoulderLeft", "mShoulderRight", BODY, { "mElbowLeft" }, "0.079 0.000 0.000" }, { "mElbowLeft", "mElbowRight", BODY, { "mWristLeft" }, "0.248 0.000 0.000" }, @@ -212,10 +212,12 @@ public: { "mWristRight", "mWristLeft", BODY, { "mHandThumb1Right", "mHandIndex1Right", "mHandMiddle1Right", "mHandRing1Right", "mHandPinky1Right" }, "-0.205 0.000 0.000", "", true }, { "mHipLeft", "mHipRight", BODY, { "mKneeLeft" }, "0.127 -0.041 0.034" }, { "mKneeLeft", "mKneeRight", BODY, { "mAnkleLeft" }, "-0.046 -0.491 -0.001" }, - { "mAnkleLeft", "mAnkleRight", BODY, {}, "0.001 -0.468 -0.029", "0.000 -0.061 0.112" }, - { "mHipRight", "mHipLeft", BODY, { "mKneeRight" }, "-0.129 -0.041 0.034", "0.000 -0.061 0.112", true }, + { "mAnkleLeft", "mAnkleRight", BODY, { "mToeLeft" }, "0.001 -0.468 -0.029" }, + { "mToeLeft", "mToeRight", BODY, {}, "0.000 0.109 0.000", "0.000 0.020 0.000" }, + { "mHipRight", "mHipLeft", BODY, { "mKneeRight" }, "-0.129 -0.041 0.034", "", true }, { "mKneeRight", "mKneeLeft", BODY, { "mAnkleRight" }, "0.049 -0.491 -0.001", "", true }, - { "mAnkleRight", "mAnkleLeft", BODY, {}, "0.000 -0.468 -0.029", "0.000 -0.061 0.112", true }, + { "mAnkleRight", "mAnkleLeft", BODY, { "mToeRight" }, "0.000 -0.468 -0.029", "", true }, + { "mToeRight", "mToeLeft", BODY, {}, "0.000 0.109 0.000", "0.000 0.020 0.000", true }, // face { "mFaceRoot", @@ -225,10 +227,10 @@ public: "mFaceForeheadLeft", "mFaceForeheadCenter", "mFaceForeheadRight", "mFaceEyebrowOuterLeft", "mFaceEyebrowCenterLeft", "mFaceEyebrowInnerLeft", "mFaceEyebrowOuterRight", "mFaceEyebrowCenterRight", "mFaceEyebrowInnerRight", - "mFaceEyeLidUpperLeft", "mFaceEyeLidLowerLeft", - "mFaceEyeLidUpperRight", "mFaceEyeLidLowerRight", + "mFaceEyeLidUpperLeft", "mFaceEyeLidLowerLeft", "mFaceEyecornerInnerLeft", + "mFaceEyeLidUpperRight", "mFaceEyeLidLowerRight", "mFaceEyecornerInnerRight", "mFaceEar1Left", "mFaceEar1Right", - "mFaceNoseLeft", "mFaceNoseCenter", "mFaceNoseRight", + "mFaceNoseBase", "mFaceNoseBridge", "mFaceNoseLeft", "mFaceNoseCenter", "mFaceNoseRight", "mFaceCheekUpperLeft", "mFaceCheekLowerLeft", "mFaceCheekUpperRight", "mFaceCheekLowerRight", "mFaceJaw", "mFaceTeethUpper" @@ -247,14 +249,18 @@ public: { "mEyeLeft", "mEyeRight", FACE, {}, "-0.036 0.079 0.098", "0.000 0.000 0.025" }, { "mEyeRight", "mEyeLeft", FACE, {}, "0.036 0.079 0.098", "0.000 0.000 0.025", true }, { "mFaceEyeLidUpperLeft", "mFaceEyeLidUpperRight", FACE, {}, "0.036 0.034 0.073", "0.000 0.005 0.027" }, + { "mFaceEyecornerInnerLeft", "mFaceEyecornerInnerRight", FACE, {}, "0.032 0.075 0.017", "0.000 0.016 0.000" }, { "mFaceEyeLidLowerLeft", "mFaceEyeLidLowerRight", FACE, {}, "0.036 0.034 0.073", "0.000 -0.007 0.024" }, { "mFaceEyeLidUpperRight", "mFaceEyeLidUpperLeft", FACE, {}, "-0.036 0.034 0.073", "0.000 0.005 0.027", true }, + { "mFaceEyecornerInnerRight", "mFaceEyecornerInnerLeft", FACE, {}, "0.032 0.075 -0.017", "0.000 0.016 0.000", true }, { "mFaceEyeLidLowerRight", "mFaceEyeLidLowerLeft", FACE, {}, "-0.036 0.034 0.073", "0.000 -0.007 0.024", true }, { "mFaceEar1Left", "mFaceEar1Right", FACE, { "mFaceEar2Left" }, "0.080 0.002 0.000", "" }, { "mFaceEar2Left", "mFaceEar2Right", FACE, {}, "0.018 0.025 -0.019", "0.000 0.033 0.000" }, { "mFaceEar1Right", "mFaceEar1Left", FACE, { "mFaceEar2Right" }, "-0.080 0.002 0.000", "", true }, { "mFaceEar2Right", "mFaceEar2Left", FACE, {}, "-0.018 0.025 -0.019", "0.000 0.033 0.000", true }, + { "mFaceNoseBase", "", FACE, {}, "-0.016 0.094 0.000", "0.000 0.014 0.000" }, + { "mFaceNoseBridge", "", FACE, {}, "0.020 0.091 0.000", "0.008 0.015 0.000" }, { "mFaceNoseLeft", "mFaceNoseRight", FACE, {}, "0.015 -0.004 0.086", "0.004 0.000 0.015" }, { "mFaceNoseCenter", "", FACE, {}, "0.000 0.000 0.102", "0.000 0.000 0.025" }, { "mFaceNoseRight", "mFaceNoseLeft", FACE, {}, "-0.015 -0.004 0.086", "-0.004 0.000 0.015", true }, @@ -343,11 +349,39 @@ public: { "mWing4Right", "mWing4Left", MISC, {}, "-0.173 0.000 -0.171", "-0.132 0.000 -0.146", true }, { "mWing4FanRight", "mWing4FanLeft", MISC, {}, "-0.173 0.000 -0.171", "-0.062 -0.159 -0.068", true }, + // Misc body parts + { "mSkull", "", MISC, {}, "0.079 0.000 0.000", "0.033 0.000 0.000" }, + { "mSpine1", "", MISC, { "mSpine2" }, "0.084 0.000 0.000" }, + { "mSpine2", "", MISC, { "mTorso", }, "-0.084 0.000 0.000" }, + { "mSpine3", "", MISC, { "mSpine4" }, "0.205 -0.015 0.000" }, + { "mSpine4", "", MISC, { "mChest", }, "-0.205 0.015 0.000" }, + // Collision Volumes + { "HEAD", "", COL_VOLUMES }, + { "NECK", "", COL_VOLUMES }, + { "L_CLAVICLE", "R_CLAVICLE", COL_VOLUMES }, + { "R_CLAVICLE", "L_CLAVICLE", COL_VOLUMES, {}, "", "", true }, + { "CHEST", "", COL_VOLUMES }, { "LEFT_PEC", "RIGHT_PEC", COL_VOLUMES }, { "RIGHT_PEC", "LEFT_PEC", COL_VOLUMES, {}, "", "", true }, + { "UPPER_BACK", "", COL_VOLUMES }, + { "LEFT_HANDLE", "RIGHT_HANDLE", COL_VOLUMES }, + { "RIGHT_HANDLE", "LEFT_HANDLE", COL_VOLUMES, {}, "", "", true }, { "BELLY", "", COL_VOLUMES }, + { "PELVIS", "", COL_VOLUMES }, { "BUTT", "", COL_VOLUMES }, + { "L_UPPER_ARM", "R_UPPER_ARM", COL_VOLUMES }, + { "R_UPPER_ARM", "L_UPPER_ARM", COL_VOLUMES, {}, "", "", true }, + { "L_LOWER_ARM", "R_LOWER_ARM", COL_VOLUMES }, + { "R_LOWER_ARM", "L_LOWER_ARM", COL_VOLUMES, {}, "", "", true }, + { "L_HAND", "R_HAND", COL_VOLUMES }, + { "R_HAND", "L_HAND", COL_VOLUMES, {}, "", "", true }, + { "L_UPPER_LEG", "R_UPPER_LEG", COL_VOLUMES }, + { "R_UPPER_LEG", "L_UPPER_LEG", COL_VOLUMES, {}, "", "", true }, + { "L_LOWER_LEG", "R_LOWER_LEG", COL_VOLUMES }, + { "R_LOWER_LEG", "L_LOWER_LEG", COL_VOLUMES, {}, "", "", true }, + { "L_FOOT", "R_FOOT", COL_VOLUMES }, + { "R_FOOT", "L_FOOT", COL_VOLUMES, {}, "", "", true }, }; public: diff --git a/indra/newview/fsprimfeedauth.cpp b/indra/newview/fsprimfeedauth.cpp new file mode 100644 index 0000000000..c264c3b8dc --- /dev/null +++ b/indra/newview/fsprimfeedauth.cpp @@ -0,0 +1,450 @@ +/** + * @file fsprimfeedauth.cpp + * @file fsprimfeedauth.h + * @brief Primfeed Authorisation workflow class + * @author beq@firestorm + * $LicenseInfo:firstyear=2025&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2025, Beq Janus + * + * 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 + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ +*/ + +/* + * Handles Primfeed authentication and authorisation through a multi-factor OAuth flow. + * + * This module integrates with Primfeed’s Third Party Viewers API. + * The authentication flow is as follows: + * 1. Initiate a login request: + * POST https://api.primfeed.com/pf/viewer/create-login-request + * Headers: + * pf-viewer-api-key: + * pf-user-uuid: + * Response: + * { "requestId": "<64-char string>" } + * + * 2. Redirect the user to: + * https://www.primfeed.com/oauth/viewer?r=&v= + * + * 3. The user is shown an approval screen. When they click Authorize, + * an in-world message is sent: + * #PRIMFEED_OAUTH: + * We intercept this code through an onChat handle then call onOauthTokenReceived(). + * + * 4. Validate the login request: + * POST https://api.primfeed.com/pf/viewer/validate-request + * Headers: + * Authorization: Bearer + * pf-viewer-api-key: + * pf-viewer-request-id: + * Response: HTTP 204 + * + * 5. Optionally, check user status: + * GET https://api.primfeed.com/pf/viewer/user + * Headers: + * Authorization: Bearer + * pf-viewer-api-key: + * Response: { "plan": "free" } (or "pro") + */ +#include "llviewerprecompiledheaders.h" +#include "fsprimfeedauth.h" +#include "fsprimfeedconnect.h" +#include "llimview.h" +#include "llnotificationsutil.h" +#include "llfloaterimnearbychathandler.h" +#include "llnotificationmanager.h" +#include "llagent.h" +#include "llevents.h" +#include "fscorehttputil.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "lluri.h" +#include "llsdjson.h" +#include + +using Callback = FSPrimfeedAuth::authorized_callback_t; + +// private instance variable +std::shared_ptr FSPrimfeedAuth::sPrimfeedAuth; +std::unique_ptr FSPrimfeedAuth::sPrimfeedAuthPump = std::make_unique("PrimfeedAuthResponse"); + +// Helper callback that unpacks HTTP POST response data. +void FSPrimfeedAuthResponse(LLSD const &aData, Callback callback) +{ + LLSD header = aData[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS][LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD( + aData[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]); + + const LLSD::Binary &rawData = aData[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); + std::string result; + result.assign(rawData.begin(), rawData.end()); + + // Assume JSON response. + + LLSD resultLLSD; + if(!result.empty()) + { + resultLLSD = LlsdFromJson(boost::json::parse(result)); + } + callback((status.getType() == HTTP_OK || + status.getType() == HTTP_NO_CONTENT), resultLLSD); +} + +void FSPrimfeedAuth::initiateAuthRequest() +{ + // This function is called to initiate the authentication request. + // It should be called when the user clicks the "Authenticate" button. + // Also triggered on opening the floater. + // The actual implementation is in the create() method. + + if (!isAuthorized()) + { + if (sPrimfeedAuth) + { + LLNotificationsUtil::add("PrimfeedAuthorizationAlreadyInProgress"); + return; + } + // If no token stored, begin the login request; otherwise check user status. + sPrimfeedAuth = FSPrimfeedAuth::create( + [](bool success, const LLSD &response) + { + LLSD event_data = response; + event_data["success"] = success; + sPrimfeedAuthPump->post(event_data); + // Now that auth is complete, clear the static pointer. + sPrimfeedAuth.reset(); + } + ); + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTING); + } + else + { + LLNotificationsUtil::add("PrimfeedAlreadyAuthorized"); + } +} + +void FSPrimfeedAuth::resetAuthStatus() +{ + sPrimfeedAuth.reset(); + gSavedPerAccountSettings.setString("FSPrimfeedOAuthToken", ""); + gSavedPerAccountSettings.setString("FSPrimfeedProfileLink", ""); + gSavedPerAccountSettings.setString("FSPrimfeedPlan", ""); + gSavedPerAccountSettings.setString("FSPrimfeedUsername", ""); + LLSD event_data; + event_data["status"] = "reset"; + event_data["success"] = "false"; + sPrimfeedAuthPump->post(event_data); + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_DISCONNECTED); +} + + +FSPrimfeedAuth::FSPrimfeedAuth(authorized_callback_t callback) + : mCallback(callback) +{ + mChatMessageConnection = LLNotificationsUI::LLNotificationManager::instance().getChatHandler()->addNewChatCallback( + [this](const LLSD &message) { + LL_DEBUGS("FSPrimfeedAuth") << "Received chat message: " << message["message"].asString() << LL_ENDL; + this->onChatMessage(message); + }); +} + +FSPrimfeedAuth::~FSPrimfeedAuth() +{ + if (mChatMessageConnection.connected()) + { + try + { + mChatMessageConnection.disconnect(); + } + catch (const std::exception& e) + { + LL_WARNS("FSPrimfeedAuth") << "Exception during chat connection disconnect: " << e.what() << LL_ENDL; + } + catch (...) + { + LL_WARNS("FSPrimfeedAuth") << "Unknown exception during chat connection disconnect." << LL_ENDL; + } + } +} + +// Factory method to create a shared pointer to FSPrimfeedAuth. +std::shared_ptr FSPrimfeedAuth::create(authorized_callback_t callback) +{ + // Ensure only one authentication attempt is in progress. + if (sPrimfeedAuth) + { + // Already in progress; return the existing instance. + return sPrimfeedAuth; + } + auto auth = std::shared_ptr(new FSPrimfeedAuth(callback)); + if(!auth) + { + return nullptr; + } + + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTING); + + // If no token stored, begin the login request; otherwise check user status. + if (gSavedPerAccountSettings.getString("FSPrimfeedOAuthToken").empty()) + { + auth->beginLoginRequest(); + } + else + { + auth->checkUserStatus(); + } + return auth; +} + +void FSPrimfeedAuth::beginLoginRequest() +{ + // Get our API key and user UUID. + std::string viewer_api_key = gSavedSettings.getString("FSPrimfeedViewerApiKey"); + std::string user_uuid = gAgent.getID().asString(); + + std::string url = "https://api.primfeed.com/pf/viewer/create-login-request"; + std::string post_data = ""; // No body parameters required. + + // Create the headers object. + LLCore::HttpHeaders::ptr_t pHeader(new LLCore::HttpHeaders()); + LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions()); + + pHeader->append("pf-viewer-api-key", viewer_api_key); + pHeader->append("pf-user-uuid", user_uuid); + + // Set up HTTP options + options->setWantHeaders(true); + options->setRetries(0); + options->setTimeout(PRIMFEED_CONNECT_TIMEOUT); + + // Capture shared_ptr to self + auto self = shared_from_this(); + + const auto end(pHeader->end()); + for (auto it(pHeader->begin()); end != it; ++it) + { + LL_DEBUGS("Primfeed") << "Header: " << it->first << " = " << it->second << LL_ENDL; + } + + // Pass both success and failure callbacks + FSCoreHttpUtil::callbackHttpPostRaw( + url, + post_data, + [self](LLSD const &aData) { + LL_DEBUGS("FSPrimfeedAuth") << "Login request response(OK): " << aData << LL_ENDL; + FSPrimfeedAuthResponse(aData, + [self](bool success, const LLSD &response) { + self->gotRequestId(success, response); + } + ); + }, + [self](LLSD const &aData) { + LL_DEBUGS("FSPrimfeedAuth") << "Login request response(FAIL): " << aData << LL_ENDL; + FSPrimfeedAuthResponse(aData, + [self](bool success, const LLSD &response) { + self->gotRequestId(success, response); + } + ); + }, + pHeader, + options + ); +} + +void FSPrimfeedAuth::gotRequestId(bool success, const LLSD &response) +{ + if (!success) + { + LLNotificationsUtil::add("PrimfeedLoginRequestFailed"); + mCallback(false, LLSD()); + return; + } + mRequestId = response["requestId"].asString(); + if (mRequestId.empty()) + { + LLNotificationsUtil::add("PrimfeedLoginRequestFailed"); + mCallback(false, LLSD()); + return; + } + // Open the browser for user approval. + std::string viewer_api_key = gSavedSettings.getString("FSPrimfeedViewerApiKey"); + std::string auth_url = "https://www.primfeed.com/oauth/viewer?r=" + mRequestId + "&v=" + viewer_api_key; + gViewerWindow->getWindow()->spawnWebBrowser(auth_url, true); + +} + +/// This function is called by the chat interceptor when the message +/// "#PRIMFEED_OAUTH: " is intercepted. +void FSPrimfeedAuth::onOauthTokenReceived(const std::string_view& oauth_token) +{ + if (oauth_token.empty()) + { + mCallback(false, LLSD()); + return; + } + mOauthToken = oauth_token; + validateRequest(); +} + +void FSPrimfeedAuth::onChatMessage(const LLSD& message) +{ + constexpr std::string_view oauth_msg_prefix = "#PRIMFEED_OAUTH: "; + const std::string msg = message["message"].asString(); + if (msg.find(std::string(oauth_msg_prefix)) == 0) + { + std::string_view oauth_token(msg.data() + oauth_msg_prefix.size(), msg.size() - oauth_msg_prefix.size()); + LL_DEBUGS("Primfeed") << "Received OAuth token: " << msg << "extracted:<" << oauth_token << ">" << LL_ENDL; + onOauthTokenReceived(oauth_token); + } +} + + +void FSPrimfeedAuth::validateRequest() +{ + // No POST body needed. + std::string post_data = ""; + std::string url = "https://api.primfeed.com/pf/viewer/validate-request"; + + // Retrieve the viewer API key. + std::string viewer_api_key = gSavedSettings.getString("FSPrimfeedViewerApiKey"); + + // Create and populate the headers. + LLCore::HttpHeaders::ptr_t pHeader(new LLCore::HttpHeaders()); + pHeader->append("Authorization", "Bearer " + mOauthToken); + pHeader->append("pf-viewer-api-key", viewer_api_key); + pHeader->append("pf-viewer-request-id", mRequestId); + + // Set HTTP options + LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions()); + options->setWantHeaders(true); + options->setRetries(0); + options->setTimeout(PRIMFEED_CONNECT_TIMEOUT); + + // print out pHeader for debuging using iterating over pHeader and using LL_DEBUGS + const auto end(pHeader->end()); + for (auto it(pHeader->begin()); end != it; ++it) + { + LL_DEBUGS("Primfeed") << "Header: " << it->first << " = " << it->second << LL_ENDL; + } + + auto self = shared_from_this(); + try + { + FSCoreHttpUtil::callbackHttpPostRaw( + url, + post_data, + [self](LLSD const &aData) { + LL_DEBUGS("FSPrimfeedAuth") << "Validation-request response(OK): " << aData << LL_ENDL; + FSPrimfeedAuthResponse(aData, + [self](bool success, const LLSD &response) { + self->gotValidateResponse(success, response); + } + ); + }, + [self](LLSD const &aData) { + LL_INFOS("FSPrimfeedAuth") << "Validation-request response(FAIL): " << aData << LL_ENDL; + FSPrimfeedAuthResponse(aData, + [self](bool success, const LLSD &response) { + self->gotValidateResponse(success, response); + } + ); + }, + pHeader, + options + ); + } + catch(const std::exception& e) + { + LL_WARNS("Primfeed") << "Primfeed validation failed " << e.what() << LL_ENDL; + } + +} + + +void FSPrimfeedAuth::gotValidateResponse(bool success, const LLSD &response) +{ + if (!success) + { + LLNotificationsUtil::add("PrimfeedValidateFailed"); + mCallback(false, response); + return; + } + checkUserStatus(); +} + +void FSPrimfeedAuth::checkUserStatus() +{ + std::string viewer_api_key = gSavedSettings.getString("FSPrimfeedViewerApiKey"); + + // Build the base URL without query parameters. + std::string url = "https://api.primfeed.com/pf/viewer/user"; + LL_DEBUGS("Primfeed") << "URL: " << url << LL_ENDL; + + // Create and populate the headers. + LLCore::HttpHeaders::ptr_t pHeader(new LLCore::HttpHeaders()); + pHeader->append("Authorization", "Bearer " + mOauthToken); + pHeader->append("pf-viewer-api-key", viewer_api_key); + + // Set HTTP options. + LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions()); + options->setWantHeaders(true); + options->setRetries(0); + options->setTimeout(PRIMFEED_CONNECT_TIMEOUT); + + // Make the HTTP GET request, passing in the headers and options. + FSCoreHttpUtil::callbackHttpGetRaw( + url, + [this](LLSD const &aData) { + LL_DEBUGS("FSPrimfeedAuth") << "Check-user-status response: " << aData << LL_ENDL; + FSPrimfeedAuthResponse(aData, [this](bool success, const LLSD &response) { + this->gotUserStatus(success, response); + }); + }, + [this](LLSD const &aData) { + LL_INFOS("FSPrimfeedAuth") << "Check-user-status response (failure): " << aData << LL_ENDL; + // Optionally, call the same processing for failure or handle separately. + FSPrimfeedAuthResponse(aData, [this](bool success, const LLSD &response){ + this->gotUserStatus(success, response); + }); + }, + pHeader, + options + ); +} + + +void FSPrimfeedAuth::gotUserStatus(bool success, const LLSD &response) +{ + LL_INFOS("Primfeed") << "User status: " << response << "(" << success << ")" << LL_ENDL; + if (success && response.has("plan")) + { + gSavedPerAccountSettings.setString("FSPrimfeedOAuthToken", mOauthToken); + gSavedPerAccountSettings.setString("FSPrimfeedPlan", response["plan"].asString()); + gSavedPerAccountSettings.setString("FSPrimfeedProfileLink", response["link"].asString()); + gSavedPerAccountSettings.setString("FSPrimfeedUsername", response["username"].asString()); + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_CONNECTED); + mCallback(true, response); + } + else + { + LLNotificationsUtil::add("PrimfeedUserStatusFailed"); + FSPrimfeedConnect::instance().setConnectionState(FSPrimfeedConnect::PRIMFEED_DISCONNECTED); + mCallback(false, response); + } +} diff --git a/indra/newview/fsprimfeedauth.h b/indra/newview/fsprimfeedauth.h new file mode 100644 index 0000000000..43fc36a937 --- /dev/null +++ b/indra/newview/fsprimfeedauth.h @@ -0,0 +1,92 @@ +/** +* @file fsprimfeedauth.h +* @brief Primfeed Authorisation workflow class +* @author beq@firestorm +* + * $LicenseInfo:firstyear=2025&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2025, Beq Janus + * + * 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 + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ +*/ +#ifndef FSPRIMFEEDAUTH_H +#define FSPRIMFEEDAUTH_H + +#include "llsd.h" +#include "llviewercontrol.h" +#include +#include + +/* +* Primfeed authentication workflow class. +* +* This class handles the Primfeed OAuth login flow and provides methods to +* check the user status and receive a callback when the authentication +* process is complete. +* based on the workflow documented at https://docs.primfeed.com/api/third-party-viewers +*/ +class FSPrimfeedAuth : public std::enable_shared_from_this +{ +public: + // Callback type: first parameter indicates success and the second holds any LLSD response. + using authorized_callback_t = std::function; + static std::shared_ptr create(authorized_callback_t callback); + static std::unique_ptr sPrimfeedAuthPump; + ~FSPrimfeedAuth(); + + // Should be called by the chat interceptor when an oauth token is received. + void onOauthTokenReceived(const std::string_view& oauth_token); + void onInstantMessage(const LLSD& message); + void onChatMessage(const LLSD& message); + + // Begin the login request flow. + void beginLoginRequest(); + // Check the user status. + void checkUserStatus(); + static bool isPendingAuth(){ return (sPrimfeedAuth != nullptr); } + static bool isAuthorized(){ return (!gSavedPerAccountSettings.getString("FSPrimfeedOAuthToken").empty()); } + static void initiateAuthRequest(); + static void resetAuthStatus(); + +private: + static std::shared_ptr sPrimfeedAuth; + + explicit FSPrimfeedAuth(authorized_callback_t callback); + authorized_callback_t mCallback; + std::string mOauthToken; + std::string mRequestId; + + // Callback when a login request response is received. + void gotRequestId(bool success, const LLSD &response); + // Validate the login request. + void validateRequest(); + // Callback when the validate response is received. + void gotValidateResponse(bool success, const LLSD &response); + // Callback when the user status response is received. + void gotUserStatus(bool success, const LLSD &response); + + boost::signals2::connection mInstantMessageConnection; + boost::signals2::connection mChatMessageConnection; + // Static flag to prevent duplicate authentication attempts. + static std::atomic sAuthorisationInProgress; + + static constexpr U32 PRIMFEED_CONNECT_TIMEOUT = 300; // 5 minute timeout should work +}; + +#endif // FSPRIMFEEDAUTH_H \ No newline at end of file diff --git a/indra/newview/fsprimfeedconnect.cpp b/indra/newview/fsprimfeedconnect.cpp new file mode 100644 index 0000000000..f6d91480a2 --- /dev/null +++ b/indra/newview/fsprimfeedconnect.cpp @@ -0,0 +1,189 @@ +/** +* @file fsprimfeedconnect.cpp +* @brief Primfeed connector class +* @author beq@firestorm +* + * $LicenseInfo:firstyear=2025&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2025, Beq Janus + * + * 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 + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ +*/ +#include "fsprimfeedconnect.h" +#include "fsprimfeedauth.h" +#include "llviewercontrol.h" +#include "llcoros.h" +#include "llsdjson.h" + +// The connector workflow for Primfeed is realtively simple and mostly just builds on top of the established Auth workflow +// and the posting endpoint documented at https://docs.primfeed.com/api/third-party-viewers#creating-a-post + +FSPrimfeedConnect::FSPrimfeedConnect() = default; + +void FSPrimfeedConnect::uploadPhoto(const LLSD& params, LLImageFormatted* image, post_callback_t callback) +{ + LL_DEBUGS("primfeed") << "uploadPhoto() called" << LL_ENDL; + if (!FSPrimfeedAuth::isAuthorized()) + { + LL_WARNS("primfeed") << "Authorization failed, aborting.\n" << LL_ENDL; + callback(false, ""); + return; + } + LL_DEBUGS("primfeed") << "Authorization successful" << LL_ENDL; + + mPostCallback = callback; + LL_DEBUGS("primfeed") << "Launching upload coroutine" << LL_ENDL; + LLCoros::instance().launch( + "FSPrimfeedConnect::uploadPhotoCoro", + [this, params, image]() { uploadPhotoCoro(params, image); } + ); +} + +void FSPrimfeedConnect::uploadPhotoCoro(const LLSD& params, LLImageFormatted* image) +{ + LL_DEBUGS("primfeed") << "Entered uploadPhotoCoro" << LL_ENDL; + setConnectionState(PRIMFEED_POSTING); + LL_DEBUGS("primfeed") << "Connection state set to PRIMFEED_POSTING" << LL_ENDL; + + const std::string fmt = (image->getCodec() == EImageCodec::IMG_CODEC_JPEG) ? "jpg" : "png"; + LL_DEBUGS("primfeed") << "Image format: " << fmt << LL_ENDL; + + const std::string boundary = "----------------------------0123456789abcdef"; + const std::string sep = "\n"; + const std::string dash = "--" + boundary; + + LL_DEBUGS("primfeed") << "Building multipart body" << LL_ENDL; + LLCore::BufferArray::ptr_t raw(new LLCore::BufferArray()); + LLCore::BufferArrayStream body(raw.get()); + auto addPart = [&](const std::string& name, const std::string& val) + { + LL_DEBUGS("primfeed") << "Adding part: " << name << "=" << val << LL_ENDL; + body << dash << sep + << "Content-Disposition: form-data; name=\"" << name << "\"" << sep << sep + << val << sep; + }; + + addPart("commercial", params["commercial"].asBoolean() ? "true" : "false"); + addPart("rating", params["rating"].asString()); + addPart("content", params["content"].asString()); + addPart("publicGallery", params["post_to_public_gallery"].asBoolean()? "true" : "false"); + + if (params.has("location") && !params["location"].asString().empty()) + { + addPart("location", params["location"].asString()); + } + + LL_DEBUGS("primfeed") << "Adding image file header" << LL_ENDL; + body << dash << sep + << "Content-Disposition: form-data; name=\"image\"; filename=\"snapshot." << fmt << "\"" << sep + << "Content-Type: image/" << fmt << sep << sep; + + U8* data = image->getData(); + S32 size = image->getDataSize(); + LL_DEBUGS("primfeed") << "Appending image data, size=" << size << LL_ENDL; + // yep this seems inefficient, but all other occurrences in the codebase do it this way. + for (S32 i = 0; i < size; ++i) + { + body << data[i]; + } + body << sep; + + body << dash << "--" << sep; + LL_DEBUGS("primfeed") << "Multipart body ready" << LL_ENDL; + + // Setup HTTP + LL_DEBUGS("primfeed") << "Preparing HTTP request" << LL_ENDL; + LLCore::HttpRequest::policy_t policy = LLCore::HttpRequest::DEFAULT_POLICY_ID; + LLCoreHttpUtil::HttpCoroutineAdapter adapter("PrimfeedUpload", policy); + LLCore::HttpRequest::ptr_t request(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions); + options->setWantHeaders(true); + + LL_DEBUGS("primfeed") << "Setting HTTP headers" << LL_ENDL; + LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders); + std::string token = gSavedPerAccountSettings.getString("FSPrimfeedOAuthToken"); + std::string apiKey = gSavedSettings.getString("FSPrimfeedViewerApiKey"); + headers->append("Authorization", "Bearer " + token); + headers->append("pf-viewer-api-key", apiKey); + headers->append("Content-Type", "multipart/form-data; boundary=" + boundary); + LL_DEBUGS("primfeed") << "Dumping HTTP headers for POST:" << LL_ENDL; + for (auto it = headers->begin(); it != headers->end(); ++it) + { + LL_DEBUGS("primfeed") << it->first << ": " << it->second << LL_ENDL; + } + LL_DEBUGS("primfeed") << "Headers set" << LL_ENDL; + + LL_DEBUGS("primfeed") << "Starting HTTP POST" << LL_ENDL; + LLSD result = adapter.postRawAndSuspend(request, + "https://api.primfeed.com/pf/viewer/post", + raw, + options, + headers); + LL_DEBUGS("primfeed") << "HTTP POST complete" << LL_ENDL; + + const LLSD::Binary &rawData = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); + std::string response_raw; + response_raw.assign(rawData.begin(), rawData.end()); + LLSD result_LLSD; + if(!response_raw.empty()) + { + result_LLSD = LlsdFromJson(boost::json::parse(response_raw)); + } + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]); + bool success = (status.getType() == HTTP_OK); + LL_DEBUGS("primfeed") << "HTTP status =" << (success?"OK":"FAIL") << " "<< status.getMessage() << LL_ENDL; + + std::string url; + if (success) + { + url = result_LLSD["url"].asString(); + LL_DEBUGS("primfeed") << "Received URL=" << url << LL_ENDL; + } + + LL_DEBUGS("primfeed") << "Invoking callback" << LL_ENDL; + mPostCallback(success, url); + setConnectionState(success ? PRIMFEED_POSTED : PRIMFEED_POST_FAILED); + LL_DEBUGS("primfeed") << "Final state set" << LL_ENDL; +} + +// Handle connection state transitions +void FSPrimfeedConnect::setConnectionState(EConnectionState state) +{ + LL_DEBUGS("primfeed") << "setConnectionState(" << state << ")" << LL_ENDL; + mConnectionState = state; +} + +FSPrimfeedConnect::EConnectionState FSPrimfeedConnect::getConnectionState() const +{ + return mConnectionState; +} + +bool FSPrimfeedConnect::isTransactionOngoing() const +{ + return (mConnectionState == PRIMFEED_CONNECTING || + mConnectionState == PRIMFEED_POSTING || + mConnectionState == PRIMFEED_DISCONNECTING); +} + +void FSPrimfeedConnect::loadPrimfeedInfo() +{ + LL_DEBUGS("primfeed") << "loadPrimfeedInfo() called" << LL_ENDL; + // Nothing to do here for Primfeed + setConnectionState(PRIMFEED_CONNECTED); +} \ No newline at end of file diff --git a/indra/newview/fsprimfeedconnect.h b/indra/newview/fsprimfeedconnect.h new file mode 100644 index 0000000000..409a93faed --- /dev/null +++ b/indra/newview/fsprimfeedconnect.h @@ -0,0 +1,82 @@ +/** +* @file fsprimfeedconect.h +* @brief Primfeed connector class +* @author beq@firestorm +* + * $LicenseInfo:firstyear=2025&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2025, Beq Janus + * + * 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 + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ +*/ +#ifndef FS_PRIMFEEDCONNECT_H +#define FS_PRIMFEEDCONNECT_H + +#include "llsingleton.h" +#include "llsd.h" +#include "llimage.h" +#include "fsprimfeedauth.h" +#include "llcorehttputil.h" +#include "bufferarray.h" +#include "llcoros.h" +#include "llviewercontrol.h" // for gSavedSettings/gSavedPerAccountSettings +#include + +// Coro based connector designed to interface with floater designed along the same principles as LLFloaterFlickr.cpp + +class FSPrimfeedConnect : public LLSingleton +{ + LLSINGLETON(FSPrimfeedConnect); +public: + // Connection states for Primfeed operations + enum EConnectionState + { + PRIMFEED_DISCONNECTED = 0, + PRIMFEED_CONNECTING, + PRIMFEED_CONNECTED, + PRIMFEED_POSTING, + PRIMFEED_POSTED, + PRIMFEED_POST_FAILED, + PRIMFEED_DISCONNECTING + }; + + // Callback invoked on post completion: success flag and URL (empty on failure) + using post_callback_t = std::function; + + // Posts a snapshot to Primfeed; requires FSPrimfeedAuth::isAuthorized() + void uploadPhoto(const LLSD& params, LLImageFormatted* image, post_callback_t callback); + + // Retrieve and update account info from Primfeed (not used kept for compatibility) + void loadPrimfeedInfo(); + + void setConnectionState(EConnectionState state); + EConnectionState getConnectionState() const; + bool isTransactionOngoing() const; + +private: + // Internal coroutine entry-point for uploads + void uploadPhotoCoro(const LLSD& params, LLImageFormatted* image); + + // Cached callback until coroutine completes + post_callback_t mPostCallback; + + // Current connection/post state + EConnectionState mConnectionState = PRIMFEED_DISCONNECTED; +}; +#endif // FS_PRIMFEEDCONNECT_H \ No newline at end of file diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 282885ff51..97dc8afa3a 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -646,6 +646,12 @@ void GLTFSceneManager::render(Asset& asset, U8 variant) return; } + if (gGLTFPBRMetallicRoughnessProgram.mGLTFVariants.size() <= variant) + { + llassert(false); // mGLTFVariants should have been initialized + return; + } + for (U32 ds = 0; ds < 2; ++ds) { RenderData& rd = asset.mRenderData[ds]; diff --git a/indra/newview/installers/windows/lang_ja.nsi b/indra/newview/installers/windows/lang_ja.nsi index 64a278637e..9033ee6c1b 100755 Binary files a/indra/newview/installers/windows/lang_ja.nsi and b/indra/newview/installers/windows/lang_ja.nsi differ diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9b60ee7c19..2fa638aded 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -234,6 +234,8 @@ #include "llfloaterreg.h" #include "llfloatersimplesnapshot.h" #include "llfloatersnapshot.h" +#include "llfloaterflickr.h" +#include "fsfloaterprimfeed.h" // Primfeed Floater #include "llsidepanelinventory.h" #include "llatmosphere.h" @@ -1764,6 +1766,8 @@ bool LLAppViewer::doFrame() gPipeline.mReflectionMapManager.update(); LLFloaterSnapshot::update(); // take snapshots LLFloaterSimpleSnapshot::update(); + LLFloaterFlickr::update(); // FIRE-35002 - Flickr preview not updating whne opened directly from tool tray icon + FSFloaterPrimfeed::update(); // Primfeed support gGLActive = false; } @@ -3808,6 +3812,7 @@ bool LLAppViewer::waitForUpdater() void LLAppViewer::writeDebugInfo(bool isStatic) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; // improve instrumentation #if LL_WINDOWS && LL_BUGSPLAT // Improve Bugsplat tracking by using attributes for certain static data items. const LLSD& info = getViewerInfo(); @@ -3836,6 +3841,7 @@ void LLAppViewer::writeDebugInfo(bool isStatic) LLSD LLAppViewer::getViewerInfo() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; // improve instrumentation // The point of having one method build an LLSD info block and the other // construct the user-visible About string is to ensure that the same info // is available to a getInfo() caller as to the user opening @@ -4148,6 +4154,7 @@ LLSD LLAppViewer::getViewerInfo() const // info["DISK_CACHE_INFO"] = LLDiskCache::getInstance()->getCacheInfo(); if (auto cache = LLDiskCache::getInstance(); cache) { + LL_PROFILE_ZONE_NAMED("gvi-getCacheInfo"); // improve instrumentation info["DISK_CACHE_INFO"] = cache->getCacheInfo(); } // @@ -6003,7 +6010,7 @@ void LLAppViewer::idle() // objects and camera should be in sync, do LOD calculations now { LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Added a max time limit to the object list updates as these updates do affect the texture system //gObjectList.updateApparentAngles(gAgent); F32 max_update_apparent_angles = 0.025f * gFrameIntervalSeconds.value(); // 20 ms/second decode time diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index de560859ec..d219cebf0e 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -644,11 +644,13 @@ int APIENTRY wWinMain(HINSTANCE hInstance, // Use the Attributes API on Windows to enhance crash metadata void LLAppViewerWin32::bugsplatAddStaticAttributes(const LLSD& info) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; #ifdef LL_BUGSPLAT auto& bugSplatMap = BugSplatAttributes::instance(); static bool write_once_after_startup = false; if (!write_once_after_startup ) { + LL_PROFILE_ZONE_NAMED("bs-st-att-once") // Only write the attributes that are fixed once after we've started. // note we might update them more than once and some/many may be empty during startup as we want to catch early crashes // once we're started we can assume they don't change for this run. @@ -689,7 +691,7 @@ void LLAppViewerWin32::bugsplatAddStaticAttributes(const LLSD& info) #if LL_DARWIN bugSplatMap.setAttribute("HiDPI", info["HIDPI"].asBoolean() ? "Enabled" : "Disabled"); #endif - bugSplatMap.setAttribute("Max Texture Size", gSavedSettings.getString("RenderMaxTextureResolution")); + bugSplatMap.setAttribute("Max Texture Size", gSavedSettings.getU32("RenderMaxTextureResolution")); } // These attributes are potentially dynamic @@ -1034,6 +1036,29 @@ bool LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) return false; } +bool LLAppViewerWin32::initWindow() +{ + // This is a workaround/hotfix for a change in Windows 11 24H2 (and possibly later) + // Where the window width and height need to correctly reflect an available FullScreen size + if (gSavedSettings.getBOOL("FullScreen")) + { + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + gSavedSettings.setU32("WindowWidth", dev_mode.dmPelsWidth); + gSavedSettings.setU32("WindowHeight", dev_mode.dmPelsHeight); + } + else + { + LL_WARNS("AppInit") << "Unable to set WindowWidth and WindowHeight for FullScreen mode" << LL_ENDL; + } + } + + return LLAppViewer::initWindow(); +} + void LLAppViewerWin32::initLoggingAndGetLastDuration() { LLAppViewer::initLoggingAndGetLastDuration(); diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 959fefd732..f044f61816 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -46,6 +46,7 @@ public: bool reportCrashToBugsplat(void* pExcepInfo) override; protected: + bool initWindow() override; // Override to initialize the viewer's window. void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info. void initConsole() override; // Initialize OS level debugging console. bool initHardwareTest() override; // Win32 uses DX9 to test hardware. diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 5542a16b2e..961c103c22 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -516,7 +516,7 @@ void LLAvatarTracker::idleNotifyObservers() void LLAvatarTracker::notifyObservers() { - if (mIsNotifyObservers || (LLStartUp::getStartupState() <= STATE_INVENTORY_CALLBACKS)) + if (mIsNotifyObservers || (LLStartUp::getStartupState() <= STATE_INVENTORY_SEND2)) { // Don't allow multiple calls. // new masks and ids will be processed later from idle. @@ -835,7 +835,7 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) mModifyMask |= LLFriendObserver::ONLINE; instance().notifyObservers(); // Skip if we had received the friends list before the inventory callbacks were properly initialized - if (LLStartUp::getStartupState() > STATE_INVENTORY_CALLBACKS) + if (LLStartUp::getStartupState() > STATE_INVENTORY_SEND2) { gInventory.notifyObservers(); } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index ca997ff7aa..ef9b585423 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -75,7 +75,7 @@ static LLStaticHashedString sColorIn("color_in"); bool LLFace::sSafeRenderSelect = true; // false -// [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer +// [FIRE-35081] Blurry prims not changing with graphics settings // Moved to allow more code to access these values const S8 FACE_IMPORTANCE_LEVEL = 4 ; const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL][2] = //{distance, importance_weight} @@ -180,7 +180,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mFaceColor = LLColor4(1,0,0,1); mImportanceToCamera = 1.f ; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings mCloseToCamera = 1.0f; // [FIRE-35081] mBoundingSphereRadius = 0.0f ; @@ -1683,7 +1683,7 @@ bool LLFace::getGeometryVolume(const LLVolume& volume, xforms = XFORM_NONE; } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Removed check for turning off animations //if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) // || isState(LLFace::RIGGED)) // [FIRE-35081] @@ -2287,7 +2287,7 @@ F32 LLFace::getTextureVirtualSize() F32 radius; F32 cos_angle_to_view_dir; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //bool in_frustum = calcPixelArea(cos_angle_to_view_dir, radius); // The mInFrustum value is now updated in calcPixelArea, so no longer need to accss the value calcPixelArea(cos_angle_to_view_dir, radius); @@ -2325,7 +2325,7 @@ F32 LLFace::getTextureVirtualSize() } face_area = LLFace::adjustPixelArea(mImportanceToCamera, face_area); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Remove the face area being affected by being partial off screen as close to screen textures can then become scaled down along with // animated textures. /* @@ -2423,7 +2423,7 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) // no rigged extents, zero out bounding box and skip update mRiggedExtents[0] = mRiggedExtents[1] = LLVector4a(0.f, 0.f, 0.f); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Set the face to be out of the frustum as the object is invalid mInFrustum = false; // [FIRE-35081] @@ -2473,7 +2473,7 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) LLVector4a x_axis; x_axis.load3(camera->getXAxis().mV); cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32(); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Added close to camera (based upon the mImportanceToCamera) where any object that is within the FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE (16.1f) // gets an extra texture scaling up. // Use positive distance to the camera and apply the multiplier based upon the texture scaled for increase in the default draw distance @@ -2488,7 +2488,7 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) if(!camera->AABBInFrustum(center, size)) { mImportanceToCamera = 0.f ; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Added real in frustum check value. Previous was only false for media textures off screen and invalid rig objects mInFrustum = false; // [FIRE-35081] @@ -2514,7 +2514,7 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) { cos_angle_to_view_dir = 1.0f ; mImportanceToCamera = 1.0f ; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings mInFrustum = true; // If the face is important to the camera, it is in the frustum mCloseToCamera = 1.0f; // [FIRE-35081] @@ -2561,7 +2561,7 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) { LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE; F32 importance = 0.f ; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Move camera out to use for the inital check for the distance to the face importance with the multiplier LLViewerCamera* camera = LLViewerCamera::getInstance(); @@ -2581,7 +2581,7 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) } S32 i = 0 ; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Added draw distance multiplier to the distance for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0] * camera->getDrawDistanceMultiplier(); ++i); // [FIRE-35081] diff --git a/indra/newview/llface.h b/indra/newview/llface.h index a3bd935760..16cd4d6eb1 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -52,7 +52,7 @@ class LLDrawInfo; class LLMeshSkinInfo; const F32 MIN_ALPHA_SIZE = 1024.f; -// [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer +// [FIRE-35081] Blurry prims not changing with graphics settings //const F32 MIN_TEX_ANIM_SIZE = 512.f; // Change the min size to const F32 MIN_TEX_ANIM_SIZE = 10.f; diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index ecf61a1e2c..65a7bb329a 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -217,7 +217,7 @@ void LLFloaterBvhPreview::setAnimCallbacks() getChild("ease_out_time")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateEaseOut, this, _1)); } -std::map LLFloaterBvhPreview::getJointAliases() +std::map > LLFloaterBvhPreview::getJointAliases() { LLPointer av = (LLVOAvatar*)mAnimPreview->getDummyAvatar(); return av->getJointAliases(); @@ -337,7 +337,7 @@ bool LLFloaterBvhPreview::loadBVH() ELoadStatus load_status = E_ST_OK; S32 line_number = 0; - std::map joint_alias_map = getJointAliases(); + auto joint_alias_map = getJointAliases(); loaderp = new LLBVHLoader(file_buffer, load_status, line_number, joint_alias_map); std::string status = getString(STATUS[load_status]); diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h index bf417fbc58..ce155246e5 100644 --- a/indra/newview/llfloaterbvhpreview.h +++ b/indra/newview/llfloaterbvhpreview.h @@ -123,7 +123,7 @@ public: // private: void setAnimCallbacks() ; - std::map getJointAliases(); + std::map > getJointAliases(); // Reload animation from disk bool loadBVH(); diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp index 64d0c9c935..196defda1f 100644 --- a/indra/newview/llfloaterflickr.cpp +++ b/indra/newview/llfloaterflickr.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" +#include "llfloatersnapshot.h" // Fix share to flickr preview again #include "llfloaterflickr.h" #include "llagent.h" @@ -243,7 +244,16 @@ void LLFlickrPhotoPanel::draw() // Draw the rest of the panel on top of it LLPanel::draw(); } - +// FIRE-35002 - Flickr preview not updating whne opened directly from tool tray icon +//static +void LLFloaterFlickr::update() +{ + if (LLFloaterReg::instanceVisible("flickr")) + { + LLFloaterSnapshotBase::ImplBase::updatePreviewList( true, true ); + } +} +// LLSnapshotLivePreview* LLFlickrPhotoPanel::getPreviewView() { LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)mPreviewHandle.get(); diff --git a/indra/newview/llfloaterflickr.h b/indra/newview/llfloaterflickr.h index e0579ba870..d24f6ec97f 100644 --- a/indra/newview/llfloaterflickr.h +++ b/indra/newview/llfloaterflickr.h @@ -136,6 +136,7 @@ public: void onOpen(const LLSD& key); LLSnapshotLivePreview* getPreviewView(); // Required for snapshot frame rendering + static void update(); // FIRE-35002 - Flickr preview not updating whne opened directly from tool tray icon private: LLFlickrPhotoPanel* mFlickrPhotoPanel; LLTextBox* mStatusErrorText; diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp index 75b9c0e052..7c81fda4ec 100644 --- a/indra/newview/llfloaterimnearbychathandler.cpp +++ b/indra/newview/llfloaterimnearbychathandler.cpp @@ -96,6 +96,13 @@ public: { ctrl->getSignal()->connect(boost::bind(&LLFloaterIMNearbyChatScreenChannel::updateToastFadingTime, this)); } + // [FIRE-35039 > FIRE-35294] Add flag to show/hide the on-screen console + ctrl = gSavedSettings.getControl("FSShowOnscreenConsole").get(); + if (ctrl) + { + ctrl->getSignal()->connect(boost::bind(&LLFloaterIMNearbyChatScreenChannel::removeToastsFromChannel, this)); + } + // [FIRE-35039 > FIRE-35294] Add flag to show/hide the on-screen console } void addChat (LLSD& chat); @@ -663,7 +670,14 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, } } - + // Hide Primfeed OAuth message from chat to prevent accidental leak of secret. + const std::string primfeed_oauth = "#PRIMFEED_OAUTH: "; + if( chat_msg.mText.compare(0, primfeed_oauth.length(), primfeed_oauth) == 0 && chat_msg.mChatType == CHAT_TYPE_IM && chat_msg.mSourceType == CHAT_SOURCE_OBJECT ) + { + // Don't show the message in chat. + return; + } + // nearby_chat->addMessage(chat_msg, true, args); if (chat_msg.mSourceType == CHAT_SOURCE_AGENT @@ -694,6 +708,14 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg, } // + // [FIRE-35039 > FIRE-35294] Add flag to show/hide the on-screen console + static LLUICachedControl showOnscreenConsole("FSShowOnscreenConsole"); + if (!showOnscreenConsole) + { + return; + } + // [FIRE-35039 > FIRE-35294] + static LLCachedControl useChatBubbles(gSavedSettings, "UseChatBubbles"); static LLCachedControl fsBubblesHideConsoleAndToasts(gSavedSettings, "FSBubblesHideConsoleAndToasts"); // [FS communication UI] diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a522a732b9..a787ac29eb 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1625,14 +1625,9 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) for (U32 j = 0; j < joint_count; ++j) { const LLVector3& joint_pos = LLVector3(skin->mAlternateBindMatrix[j].getTranslation()); - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; + LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; - //LLJoint* pJoint = LLModelPreview::lookupJointByName(skin->mJointNames[j], mModelPreview); - LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j].mName]; - - LLJoint* pJoint = LLModelPreview::lookupJointByName(skin->mJointNames[j].mName, mModelPreview); - // + LLJoint* pJoint = LLModelPreview::lookupJointByName(skin->mJointNames[j], mModelPreview); if (pJoint) { // see how voavatar uses aboveJointPosThreshold @@ -1661,9 +1656,7 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) { for (U32 j = 0; j < joint_count; ++j) { - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; - LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j].mName]; + LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; data.mModelsNoOverrides.insert(model->getName()); } } @@ -1678,7 +1671,7 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) { // Populate table - std::map joint_alias_map; + std::map> joint_alias_map; mModelPreview->getJointAliases(joint_alias_map); S32 conflicts = 0; diff --git a/indra/newview/llfloaternewfeaturenotification.cpp b/indra/newview/llfloaternewfeaturenotification.cpp index 369727ff1e..9ea51451ad 100644 --- a/indra/newview/llfloaternewfeaturenotification.cpp +++ b/indra/newview/llfloaternewfeaturenotification.cpp @@ -45,10 +45,27 @@ bool LLFloaterNewFeatureNotification::postBuild() const std::string title_txt = "title_txt"; const std::string dsc_txt = "description_txt"; - std::string feature = "_" + getKey().asString(); - - getChild(title_txt)->setValue(getString(title_txt + feature)); - getChild(dsc_txt)->setValue(getString(dsc_txt + feature)); + // FIRE-35393 stop crashing just cos whirly does something daft and blames Atlas for it + std::string feature = getKey().asString(); + if(feature.empty() ) + { + LL_WARNS("FloaterNewFeature") << "Unexpected failure - No feature name NewFeatureNotification." << LL_ENDL; + return false; + } + if (!hasString( title_txt + "_" + feature ) ) + { + LL_WARNS("FloaterNewFeature") << "No string for " << title_txt + "_" + feature << LL_ENDL; + return false; + } + if (!hasString( dsc_txt + "_" + feature ) ) + { + LL_WARNS("FloaterNewFeature") << "No string for " << dsc_txt + "_" + feature << LL_ENDL; + return false; + } + // + + getChild(title_txt)->setValue(getString(title_txt + "_" + feature)); + getChild(dsc_txt)->setValue(getString(dsc_txt + "_" + feature)); if (getKey().asString() == "gltf") { diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index ac545cfe87..10e9fd3d5e 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -30,6 +30,7 @@ #include "llfloaterreg.h" #include "llfloaterflickr.h" // Share to Flickr +#include "fsfloaterprimfeed.h" // Share to Primfeed #include "llimagefiltersmanager.h" #include "llcheckboxctrl.h" #include "llcombobox.h" @@ -1485,12 +1486,12 @@ bool LLFloaterSnapshot::isWaitingState() // FIRE-35002 - Post to flickr broken, improved solution // bool LLFloaterSnapshotBase::ImplBase::updatePreviewList(bool initialized) -bool LLFloaterSnapshotBase::ImplBase::updatePreviewList(bool initialized, bool have_flickr) +bool LLFloaterSnapshotBase::ImplBase::updatePreviewList(bool initialized, bool have_socials) // { // Share to Flickr //if (!initialized) - if (!initialized && !have_flickr) + if (!initialized && !have_socials) // return false; @@ -1509,16 +1510,18 @@ void LLFloaterSnapshotBase::ImplBase::updateLivePreview() { // don't update preview for hidden floater // FIRE-35002 - Post to flickr broken - LLFloaterFlickr* floater_flickr = LLFloaterReg::findTypedInstance("flickr"); - auto have_flickr = floater_flickr != nullptr; + bool have_socials = ( + LLFloaterReg::findTypedInstance("flickr") != nullptr || + LLFloaterReg::findTypedInstance("primfeed") != nullptr + ); if ( ((mFloater && mFloater->isInVisibleChain()) || - have_flickr) && - ImplBase::updatePreviewList(true, have_flickr)) + have_socials) && + ImplBase::updatePreviewList(true, have_socials)) // { LL_DEBUGS() << "changed" << LL_ENDL; updateControls(mFloater); - } + } } //static diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index e6c4025bb3..934893b50b 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -123,7 +123,7 @@ public: virtual EStatus getStatus() const { return mStatus; } virtual void setNeedRefresh(bool need); - static bool updatePreviewList(bool initialized, bool have_flickr = false); // FIRE-35002 - Post to flickr broken, improved solution + static bool updatePreviewList(bool initialized, bool have_socials = false); // FIRE-35002 - Post to flickr broken, improved solution void setAdvanced(bool advanced) { mAdvanced = advanced; } void setSkipReshaping(bool skip) { mSkipReshaping = skip; } diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index bae3b9fb18..4c102756c2 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -433,10 +433,13 @@ bool LLFloaterWorldMap::postBuild() F32 slider_zoom = mMapView->getZoom(); mZoomSlider->setValue(slider_zoom); + mTrackCtrlsPanel = getChild("layout_panel_4"); + mSearchButton = getChild("DoSearch"); + // Use own expand/collapse function //getChild("expand_btn_panel")->setMouseDownCallback(boost::bind(&LLFloaterWorldMap::onExpandCollapseBtn, this)); - setDefaultBtn(NULL); + mTrackCtrlsPanel->setDefaultBtn(nullptr); onChangeMaturity(); @@ -784,7 +787,7 @@ void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string& { LLTracker::stopTracking(false); } - setDefaultBtn("Teleport"); + mTrackCtrlsPanel->setDefaultBtn(mTeleportButton); } void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id ) @@ -829,7 +832,7 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id ) { LLTracker::stopTracking(false); } - setDefaultBtn("Teleport"); + mTrackCtrlsPanel->setDefaultBtn(mTeleportButton); } @@ -838,7 +841,7 @@ void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info) mShowParcelInfo = false; mTrackedStatus = LLTracker::TRACKING_LOCATION; LLTracker::trackLocation(event_info.getGlobalPosition(), event_info.getName(), event_info.getToolTip(), LLTracker::LOCATION_EVENT); - setDefaultBtn("Teleport"); + mTrackCtrlsPanel->setDefaultBtn(mTeleportButton); } void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item) @@ -846,7 +849,7 @@ void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item) mShowParcelInfo = false; mTrackedStatus = LLTracker::TRACKING_LOCATION; LLTracker::trackLocation(item.getGlobalPosition(), item.getName(), item.getToolTip(), LLTracker::LOCATION_ITEM); - setDefaultBtn("Teleport"); + mTrackCtrlsPanel->setDefaultBtn(mTeleportButton); } void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) @@ -860,7 +863,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) S32 world_x = S32(pos_global.mdV[0] / 256); S32 world_y = S32(pos_global.mdV[1] / 256); LLWorldMapMessage::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true); - setDefaultBtn(""); + mTrackCtrlsPanel->setDefaultBtn(nullptr); // clicked on a non-region - turn off coord display enableTeleportCoordsDisplay( false ); @@ -874,7 +877,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) LLTracker::stopTracking(false); LLWorldMap::getInstance()->setTracking(pos_global); LLWorldMap::getInstance()->setTrackingInvalid(); - setDefaultBtn(""); + mTrackCtrlsPanel->setDefaultBtn(nullptr); // clicked on a down region - turn off coord display enableTeleportCoordsDisplay( false ); @@ -925,7 +928,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) // we have a valid region - turn on coord display enableTeleportCoordsDisplay( true ); - setDefaultBtn("Teleport"); + mTrackCtrlsPanel->setDefaultBtn(mTeleportButton); } // enable/disable teleport destination coordinates @@ -1085,9 +1088,9 @@ void LLFloaterWorldMap::updateLocation() // mSLURL = LLSLURL(sim_name, pos_global); // [FIRE-35268] OpenSim support for when on other grids if (LLGridManager::getInstance()->isInSecondLife()) - mSLURL = LLSLURL(sim_info->getName(), gAgent.getPositionAgent()); + mSLURL = LLSLURL(sim_info->getName(), sim_info->getGlobalOrigin(), pos_global); else - mSLURL = LLSLURL(LFSimFeatureHandler::instance().hyperGridURL(), sim_info->getName(), gAgent.getPositionAgent()); + mSLURL = LLSLURL(LFSimFeatureHandler::instance().hyperGridURL(), sim_info->getName(), sim_info->getGlobalOrigin(), pos_global); // } // @@ -1131,7 +1134,7 @@ void LLFloaterWorldMap::trackURL(const std::string& region_name, S32 x_coord, S3 local_pos.mV[VZ] = (F32)z_coord; LLVector3d global_pos = sim_info->getGlobalPos(local_pos); trackLocation(global_pos); - setDefaultBtn("Teleport"); + mTrackCtrlsPanel->setDefaultBtn(mTeleportButton); } else { @@ -1569,11 +1572,11 @@ void LLFloaterWorldMap::updateSearchEnabled() if (childHasKeyboardFocus("location") && mLocationEditor->getValue().asString().length() > 0) { - setDefaultBtn("DoSearch"); + mTrackCtrlsPanel->setDefaultBtn(mSearchButton); } else { - setDefaultBtn(NULL); + mTrackCtrlsPanel->setDefaultBtn(nullptr); } } @@ -2033,7 +2036,7 @@ void LLFloaterWorldMap::onCommitSearchResult() mLocationEditor->setValue(sim_name); trackLocation(pos_global); - setDefaultBtn("Teleport"); + mTrackCtrlsPanel->setDefaultBtn(mTeleportButton); break; } } diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index d71ae9e88c..f7c9482b23 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -232,6 +232,7 @@ private: LLButton* mShowDestinationButton = nullptr; LLButton* mCopySlurlButton = nullptr; LLButton* mGoHomeButton = nullptr; + LLButton* mSearchButton = nullptr; LLCheckBoxCtrl* mPeopleCheck = nullptr; LLCheckBoxCtrl* mInfohubCheck = nullptr; @@ -258,6 +259,8 @@ private: LLSliderCtrl* mZoomSlider = nullptr; + LLPanel* mTrackCtrlsPanel = nullptr; + boost::signals2::connection mTeleportFinishConnection; }; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 5653d040e3..0be2171a14 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -3914,16 +3914,55 @@ LLUUID LLIMMgr::addSession( //works only for outgoing ad-hoc sessions if (new_session && ((IM_NOTHING_SPECIAL == dialog) || (IM_SESSION_P2P_INVITE == dialog) || (IM_SESSION_CONFERENCE_START == dialog)) && - ids.size()) + // [FIRE-34494] fix unable to open an IM with someone who started a group chat + //ids.size()) + !ids.empty()) + // { session = LLIMModel::getInstance()->findAdHocIMSession(ids); if (session) { - new_session = false; - session_id = session->mSessionID; +// [FIRE-34494] fix unable to open an IM with someone who started a group chat + // new_session = false; + // session_id = session->mSessionID; + + // Protect against wrong session type reuse (e.g., conference reused for IM) + if (session->mType != dialog) + { + LL_WARNS("IMVIEW") << "Discarding mismatched session type reuse: expected " + << dialog << " but found " << session->mType + << " for session " << session->mSessionID + << ". This may indicate improper reuse of a session object." << LL_ENDL; + session = nullptr; + new_session = true; + session_id = computeSessionID(dialog, other_participant_id); + } + else + { + new_session = false; + session_id = session->mSessionID; + } } } + if (session && session->mType != dialog) + { + // Prevent reusing a session of the wrong type + session = nullptr; + new_session = true; + + // Recompute session ID depending on dialog type + if (dialog == IM_SESSION_CONFERENCE_START) + { + session_id.generate(); + } + else + { + session_id = computeSessionID(dialog, other_participant_id); + } +// + } + //Notify observers that a session was added if (new_session) { diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 228aa5bd1e..f29bc9782b 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -346,6 +346,15 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) LL_DEBUGS("LLLogin") << "reason " << reason_response << " message " << message_response << LL_ENDL; + + if (response.has("mfa_hash")) + { + mRequestData["params"]["mfa_hash"] = response["mfa_hash"]; + mRequestData["params"]["token"] = ""; + + saveMFAHash(response); + } + // For the cases of critical message or TOS agreement, // start the TOS dialog. The dialog response will be handled // by the LLLoginInstance::handleTOSResponse() callback. @@ -609,6 +618,24 @@ bool LLLoginInstance::handleMFAChallenge(LLSD const & notif, LLSD const & respon return true; } +void LLLoginInstance::saveMFAHash(LLSD const& response) +{ + std::string grid(LLGridManager::getInstance()->getGridId()); + std::string user_id(LLStartUp::getUserId()); + + // Only save mfa_hash for future logins if the user wants their info remembered. + if (response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && LLLoginInstance::getInstance()->saveMFA()) + { + gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); + } + else if (!LLLoginInstance::getInstance()->saveMFA()) + { + gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid, user_id); + } + // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically + gSecAPIHandler->syncProtectedMap(); +} + std::string construct_start_string() { std::string start; diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index e5cb14b262..3634dc39bc 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -73,6 +73,8 @@ public: void setNotificationsInterface(LLNotificationsInterface* ni) { mNotifications = ni; } LLNotificationsInterface& getNotificationsInterface() const { return *mNotifications; } + void saveMFAHash(LLSD const& response); + private: typedef std::shared_ptr ResponsePtr; void constructAuthParams(LLPointer user_credentials); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 30b77fc62d..89208b27ec 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1909,42 +1909,36 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) //static void LLMeshRepoThread::incActiveLODRequests() { - LLMutexLock lock(gMeshRepo.mThread->mMutex); ++LLMeshRepoThread::sActiveLODRequests; } //static void LLMeshRepoThread::decActiveLODRequests() { - LLMutexLock lock(gMeshRepo.mThread->mMutex); --LLMeshRepoThread::sActiveLODRequests; } //static void LLMeshRepoThread::incActiveHeaderRequests() { - LLMutexLock lock(gMeshRepo.mThread->mMutex); ++LLMeshRepoThread::sActiveHeaderRequests; } //static void LLMeshRepoThread::decActiveHeaderRequests() { - LLMutexLock lock(gMeshRepo.mThread->mMutex); --LLMeshRepoThread::sActiveHeaderRequests; } //static void LLMeshRepoThread::incActiveSkinRequests() { - LLMutexLock lock(gMeshRepo.mThread->mMutex); ++LLMeshRepoThread::sActiveSkinRequests; } //static void LLMeshRepoThread::decActiveSkinRequests() { - LLMutexLock lock(gMeshRepo.mThread->mMutex); --LLMeshRepoThread::sActiveSkinRequests; } @@ -4665,13 +4659,20 @@ void LLMeshRepository::notifyLoadedMeshes() { LLMutexTrylock lock1(mMeshMutex); LLMutexTrylock lock2(mThread->mMutex); + LLMutexTrylock lock3(mThread->mHeaderMutex); + LLMutexTrylock lock4(mThread->mPendingMutex); static U32 hold_offs(0); - if (! lock1.isLocked() || ! lock2.isLocked()) + if (! lock1.isLocked() || ! lock2.isLocked() || ! lock3.isLocked() || ! lock4.isLocked()) { // If we can't get the locks, skip and pick this up later. + // Eventually thread queue will be free enough ++hold_offs; sMaxLockHoldoffs = llmax(sMaxLockHoldoffs, hold_offs); + if (hold_offs > 4) + { + LL_WARNS_ONCE() << "High mesh thread holdoff" << LL_ENDL; + } return; } hold_offs = 0; @@ -4732,6 +4733,7 @@ void LLMeshRepository::notifyLoadedMeshes() if (mPendingRequests.size() > push_count) { + LL_PROFILE_ZONE_NAMED("Mesh score_map"); // More requests than the high-water limit allows so // sort and forward the most important. @@ -4782,8 +4784,6 @@ void LLMeshRepository::notifyLoadedMeshes() std::partial_sort(mPendingRequests.begin(), mPendingRequests.begin() + push_count, mPendingRequests.end(), PendingRequestBase::CompareScoreGreater()); } - LLMutexTrylock lock3(mThread->mHeaderMutex); - LLMutexTrylock lock4(mThread->mPendingMutex); while (!mPendingRequests.empty() && push_count > 0) { std::unique_ptr& req_p = mPendingRequests.front(); @@ -6238,13 +6238,20 @@ bool LLMeshRepository::meshUploadEnabled() bool LLMeshRepository::meshRezEnabled() { static LLCachedControl mesh_enabled(gSavedSettings, "MeshEnabled"); - LLViewerRegion *region = gAgent.getRegion(); - if(mesh_enabled && - region) +// FIRE-35602 etc - Mesh not appearing after TP/login (opensim only) +// For OpenSim there is still an outside chance that mesh rezzing is disabled on the sim/region +// restore the old behaviour but keep the bias to mesh_enabled == true in the underlying checks. +#ifdef OPENSIM + if (LLGridManager::instance().isInOpenSim()) { - return region->meshRezEnabled(); + if (LLViewerRegion* region = gAgent.getRegion(); mesh_enabled && region) + { + return region->meshRezEnabled(); + } } - return false; +#endif // OPENSIM +// + return mesh_enabled; } // Threading: main thread only diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 8fcef7d1e2..342068ab04 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1020,7 +1020,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable clearGLODGroup(); } // - std::map joint_alias_map; + std::map> joint_alias_map; getJointAliases(joint_alias_map); LLHandle preview_handle = getHandle(); @@ -4185,10 +4185,7 @@ LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque) LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); if (pPreview) { -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// return pPreview->getPreviewAvatar()->getJoint(str); - return pPreview->getPreviewAvatar()->getJoint( JointKey::construct( str ) ); -// + return pPreview->getPreviewAvatar()->getJoint(str); } return NULL; } diff --git a/indra/newview/llmorphview.cpp b/indra/newview/llmorphview.cpp index 693915e813..cfbfa0ac27 100644 --- a/indra/newview/llmorphview.cpp +++ b/indra/newview/llmorphview.cpp @@ -131,10 +131,7 @@ void LLMorphView::updateCamera() { if (!mCameraTargetJoint) { -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// setCameraTargetJoint( gAgentAvatarp->getJoint( "mHead" ) ); - setCameraTargetJoint( gAgentAvatarp->getJoint( JointKey::construct( "mHead" ) ) ); -// + setCameraTargetJoint( gAgentAvatarp->getJoint( "mHead" ) ); } if (!isAgentAvatarValid()) return; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index a7725d8899..07a168612a 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1316,15 +1316,11 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, bool show, bo value_map_t sorted_params; getSortedParams(sorted_params, edit_group); - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //LLJoint* jointp = gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ); - LLJoint* jointp = gAgentAvatarp->getJoint( JointKey::construct( subpart_entry->mTargetJoint ) ); + LLJoint* jointp = gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ); if (!jointp) { - //jointp = gAgentAvatarp->getJoint( "mHead" ); - jointp = gAgentAvatarp->getJoint( JointKey::construct( "mHead" ) ); + jointp = gAgentAvatarp->getJoint( "mHead" ); } - // buildParamList(panel_list, sorted_params, tab, jointp); @@ -1440,11 +1436,7 @@ void LLPanelEditWearable::changeCamera(U8 subpart) } // Update the camera -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) ); - gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( JointKey::construct( subpart_entry->mTargetJoint ) ) ); -// ND> - + gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) ); gMorphView->setCameraTargetOffset( subpart_entry->mTargetOffset ); gMorphView->setCameraOffset( subpart_entry->mCameraOffset ); if (gSavedSettings.getBOOL("AppearanceCameraMovement")) diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 33bd128959..b53bd76086 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -5540,6 +5540,11 @@ void LLPanelFace::changePrecision(S32 decimal_precision) mBumpyRotate->setPrecision(decimal_precision); mShinyRotate->setPrecision(decimal_precision); mTexRepeat->setPrecision(decimal_precision); + mPBRScaleU->setPrecision(decimal_precision); + mPBRScaleV->setPrecision(decimal_precision); + mPBRRotate->setPrecision(decimal_precision); + mPBROffsetU->setPrecision(decimal_precision); + mPBROffsetV->setPrecision(decimal_precision); } // diff --git a/indra/newview/llpaneloutfitsinventory.cpp b/indra/newview/llpaneloutfitsinventory.cpp index 634a36b371..b6ae97e834 100644 --- a/indra/newview/llpaneloutfitsinventory.cpp +++ b/indra/newview/llpaneloutfitsinventory.cpp @@ -116,6 +116,9 @@ bool LLPanelOutfitsInventory::postBuild() getChild(SAVE_BTN)->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::saveOutfit, this, false)); getChild(SAVE_AS_BTN)->setCommitCallback(boost::bind(&LLPanelOutfitsInventory::saveOutfit, this, true)); + // FIRE-17626: Attachment count in appearance floater + mTempAttachmentUpdateTimer.start(); + return true; } @@ -261,6 +264,20 @@ void LLPanelOutfitsInventory::onSave() } // FIRE-17626: Attachment count in appearance floater +void LLPanelOutfitsInventory::draw() +{ + if (mTempAttachmentUpdateTimer.checkExpirationAndReset(1.f)) + { + if (U32 tempAttachmentCount = (U32)LLAgentWearables::getTempAttachments().size(); tempAttachmentCount != mCurrentTempAttachmentCount) + { + mCurrentTempAttachmentCount = tempAttachmentCount; + onCOFChanged(); + } + } + + LLPanel::draw(); +} + void LLPanelOutfitsInventory::onCOFChanged() { if (!isAgentAvatarValid()) @@ -273,7 +290,7 @@ void LLPanelOutfitsInventory::onCOFChanged() LLInventoryModel::cat_array_t cats; LLIsType is_of_type(LLAssetType::AT_OBJECT); gInventory.collectDescendentsIf(cof, cats, obj_items, LLInventoryModel::EXCLUDE_TRASH, is_of_type); - U32 attachments = static_cast(obj_items.size()); + U32 attachments = static_cast(obj_items.size()) + mCurrentTempAttachmentCount; LLStringUtil::format_map_t args; args["COUNT"] = llformat("%d", attachments); diff --git a/indra/newview/llpaneloutfitsinventory.h b/indra/newview/llpaneloutfitsinventory.h index dc64661b3b..adeed9d28d 100644 --- a/indra/newview/llpaneloutfitsinventory.h +++ b/indra/newview/llpaneloutfitsinventory.h @@ -52,6 +52,8 @@ public: /*virtual*/ bool postBuild(); /*virtual*/ void onOpen(const LLSD& key); + void draw(); // FIRE-17626: Attachment count in appearance floater + void onSearchEdit(const std::string& string); void onSave(); void saveOutfit(bool as_new = false); @@ -91,6 +93,10 @@ private: // FIRE-17626: Attachment count in appearance floater LLInventoryCategoriesObserver* mCategoriesObserver; void onCOFChanged(); + + U32 mCurrentTempAttachmentCount{ 0 }; + + LLFrameTimer mTempAttachmentUpdateTimer; // ////////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelsnapshotoptions.cpp b/indra/newview/llpanelsnapshotoptions.cpp index 58340a98d9..13aae9c37a 100644 --- a/indra/newview/llpanelsnapshotoptions.cpp +++ b/indra/newview/llpanelsnapshotoptions.cpp @@ -32,6 +32,7 @@ #include "llfloatersnapshot.h" // FIXME: create a snapshot model #include "llfloaterreg.h" #include "llfloaterflickr.h" // Share to Flickr +#include "fsfloaterprimfeed.h" // Share to Primfeed /** * Provides several ways to save a snapshot. @@ -52,6 +53,7 @@ private: void onSaveToInventory(); void onSaveToComputer(); void onSendToFlickr(); // Share to Flickr + void onSendToPrimfeed(); // Share to Primfeed LLFloaterSnapshotBase* mSnapshotFloater; }; @@ -65,6 +67,7 @@ LLPanelSnapshotOptions::LLPanelSnapshotOptions() mCommitCallbackRegistrar.add("Snapshot.SaveToInventory", boost::bind(&LLPanelSnapshotOptions::onSaveToInventory, this)); mCommitCallbackRegistrar.add("Snapshot.SaveToComputer", boost::bind(&LLPanelSnapshotOptions::onSaveToComputer, this)); mCommitCallbackRegistrar.add("Snapshot.SendToFlickr", boost::bind(&LLPanelSnapshotOptions::onSendToFlickr, this)); // Share to Flickr + mCommitCallbackRegistrar.add("Snapshot.SendToPrimfeed", boost::bind(&LLPanelSnapshotOptions::onSendToPrimfeed, this)); // Share to Primfeed } // virtual @@ -113,11 +116,23 @@ void LLPanelSnapshotOptions::onSendToFlickr() { LLFloaterReg::hideInstance("snapshot"); - LLFloaterFlickr* flickr_floater = dynamic_cast(LLFloaterReg::getInstance("flickr")); - if (flickr_floater) + if (auto flickr_floater = LLFloaterReg::getTypedInstance("flickr")) { flickr_floater->showPhotoPanel(); } LLFloaterReg::showInstance("flickr"); } // + +// Share to Primfeed +void LLPanelSnapshotOptions::onSendToPrimfeed() +{ + LLFloaterReg::hideInstance("snapshot"); + + if (auto primfeed_floater = LLFloaterReg::getTypedInstance("primfeed")) + { + primfeed_floater->showPhotoPanel(); + } + LLFloaterReg::showInstance("primfeed"); +} +// diff --git a/indra/newview/llpresetsmanager.cpp b/indra/newview/llpresetsmanager.cpp index d4da3bfbe5..ebc332caa1 100644 --- a/indra/newview/llpresetsmanager.cpp +++ b/indra/newview/llpresetsmanager.cpp @@ -538,17 +538,22 @@ void LLPresetsManager::loadPreset(const std::string& subdirectory, std::string n { gSavedSettings.setString("PresetGraphicActive", name); + // [FIRE-35390] Old viewer presets have these as true and 0.7, whereas the equivalent on modern viewers is false and 1.0 + if (auto control = gSavedSettings.getControl("RenderSkyAutoAdjustLegacy")) + control->resetToDefault(true); + if (auto control = gSavedSettings.getControl("RenderSkyAmbientScale")) + control->resetToDefault(true); + // + // Update indirect controls LLAvatarComplexityControls::setIndirectControls(); - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); - if (instance) + if (LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences")) { instance->refreshEnabledGraphics(); } // Graphic preset controls independent from XUI - FloaterQuickPrefs* phototools = LLFloaterReg::findTypedInstance(PHOTOTOOLS_FLOATER); - if (phototools) + if (FloaterQuickPrefs* phototools = LLFloaterReg::findTypedInstance(PHOTOTOOLS_FLOATER)) { phototools->refreshSettings(); } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index b13d710a29..f0013d69bd 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -7970,19 +7970,20 @@ bool LLSelectMgr::canSelectObject(LLViewerObject* object, bool ignore_select_own // only select my own objects return false; } + + // FIRE-14593: Option to select only copyable objects + if (!object->permCopy() && gSavedSettings.getBOOL("FSSelectCopyableOnly")) + { + return false; + } + // + // FIRE-17696: Option to select only locked objects + if (gSavedSettings.getBOOL("FSSelectLockedOnly") && object->permMove() && !object->isPermanentEnforced()) + { + return false; + } + // // Can't select objects that are not owned by you or group } - // FIRE-14593: Option to select only copyable objects - if (!object->permCopy() && gSavedSettings.getBOOL("FSSelectCopyableOnly")) - { - return false; - } - // - // FIRE-17696: Option to select only locked objects - if (gSavedSettings.getBOOL("FSSelectLockedOnly") && object->permMove() && !object->isPermanentEnforced()) - { - return false; - } - // // Can't select orphans if (object->isOrphaned()) return false; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 2fe716fa91..15d5ff11d4 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -54,10 +54,7 @@ void dump_avatar_and_skin_state(const std::string& reason, LLVOAvatar *avatar, c { LL_WARNS("Avatar") << "skin joint idx " << j << " name [" << skin->mJointNames[j] << "] num " << skin->mJointNums[j] << LL_ENDL; - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //const std::string& name = skin->mJointNames[j]; - const std::string& name = skin->mJointNames[j].mName; - // + const std::string& name = skin->mJointNames[j]; S32 joint_num = skin->mJointNums[j]; LLJoint *name_joint = avatar->getJoint(name); @@ -119,14 +116,9 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin // needed for handling of any legacy bad data. if (!avatar->getJoint(skin->mJointNames[j])) { - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //LL_DEBUGS("Avatar") << avatar->getDebugName() << " mesh rigged to invalid joint " << skin->mJointNames[j] << LL_ENDL; - //LL_WARNS_ONCE("Avatar") << avatar->getDebugName() << " mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL; - //skin->mJointNames[j] = "mPelvis"; - LL_DEBUGS("Avatar") << avatar->getDebugName() << " mesh rigged to invalid joint " << skin->mJointNames[j].mName << LL_ENDL; - LL_WARNS_ONCE("Avatar") << avatar->getDebugName() << " mesh rigged to invalid joint" << skin->mJointNames[j].mName << LL_ENDL; - skin->mJointNames[j] = JointKey::construct("mPelvis"); - // + LL_DEBUGS("Avatar") << avatar->getDebugName() << " mesh rigged to invalid joint " << skin->mJointNames[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getDebugName() << " mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL; + skin->mJointNames[j] = "mPelvis"; skin->mJointNumsInitialized = false; // force update after names change. } } diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index d9d21fe700..1270457abc 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -36,6 +36,7 @@ #include "llfloaterperms.h" #include "llfloaterreg.h" #include "llfloaterflickr.h" // Share to Flickr +#include "fsfloaterprimfeed.h" // Share to Primfeed #include "llimagefilter.h" #include "llimagefiltersmanager.h" #include "llimagebmp.h" diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 85541d8175..b73a5ef9f6 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1950,9 +1950,9 @@ bool idle_startup() // Wait for notification confirmation if (STATE_LOGIN_CONFIRM_NOTIFICATON == LLStartUp::getStartupState()) { - display_startup(); + do_startup_frame(); gViewerWindow->getProgressView()->setVisible(false); - display_startup(); + do_startup_frame(); ms_sleep(1); return false; } @@ -2298,10 +2298,10 @@ bool idle_startup() //so I just moved nearby history loading a few states further if (gSavedPerAccountSettings.getBOOL("LogShowHistory")) { - FSFloaterNearbyChat* nearby_chat = FSFloaterNearbyChat::getInstance(); - if (nearby_chat) nearby_chat->loadHistory(); + if (FSFloaterNearbyChat* nearby_chat = FSFloaterNearbyChat::getInstance()) + nearby_chat->loadHistory(); } - display_startup(); + do_startup_frame(); // [FS communication UI] // FIRE-18250: Option to disable default eye movement @@ -2549,13 +2549,14 @@ bool idle_startup() LL_INFOS() << "Requesting Money Balance" << LL_ENDL; LLStatusBar::sendMoneyBalanceRequest(); - do_startup_frame(); // Moved before inventory creation. // request all group information LL_INFOS("Agent_GroupData") << "GROUPDEBUG: Requesting Agent Data during startup" << LL_ENDL; gAgent.sendAgentDataUpdateRequest(); - display_startup(); // + + do_startup_frame(); + // Inform simulator of our language preference LLAgentLanguage::update(); @@ -2808,7 +2809,7 @@ bool idle_startup() // Create the inventory views LL_INFOS() << "Creating Inventory Views" << LL_ENDL; LLFloaterReg::getInstance("inventory"); - //do_startup_frame(); + do_startup_frame(); // [RLVa:KB] - Checked: RLVa-1.1.0 if (RlvHandler::isEnabled()) @@ -2898,7 +2899,7 @@ bool idle_startup() //ok, we're done, set it back to false. gSavedSettings.setBOOL("FSFirstRunAfterSettingsRestore", false); } - display_startup(); + do_startup_frame(); // if (gSavedSettings.getBOOL("HelpFloaterOpen")) @@ -3074,7 +3075,7 @@ bool idle_startup() } } #endif // OPENSIM - display_startup(); + do_startup_frame(); // LLStartUp::setStartupState( STATE_PRECACHE ); @@ -4972,24 +4973,7 @@ bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token); } - // Only save mfa_hash for future logins if the user wants their info remembered. - if(response.has("mfa_hash") - && gSavedSettings.getBOOL("RememberUser") - && LLLoginInstance::getInstance()->saveMFA()) - { - std::string grid(LLGridManager::getInstance()->getGridId()); - std::string user_id(gUserCredential->userID()); - gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]); - // TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically - gSecAPIHandler->syncProtectedMap(); - } - else if (!LLLoginInstance::getInstance()->saveMFA()) - { - std::string grid(LLGridManager::getInstance()->getGridId()); - std::string user_id(gUserCredential->userID()); - gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid, user_id); - gSecAPIHandler->syncProtectedMap(); - } + LLLoginInstance::getInstance()->saveMFAHash(response); // OpenSim legacy economy support #ifdef OPENSIM @@ -5092,6 +5076,7 @@ bool process_login_success_response(U32 &first_sim_size_x, U32 &first_sim_size_y } // + bool success = false; // JC: gesture loading done below, when we have an asset system // in place. Don't delete/clear gUserCredentials until then. diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp index 3d90734d96..3c20615a24 100644 --- a/indra/newview/llteleporthistory.cpp +++ b/indra/newview/llteleporthistory.cpp @@ -44,6 +44,10 @@ #include "llavatarname.h" #include "llavatarnamecache.h" +#include "llviewernetwork.h" // Access to GridManager +#include "lfsimfeaturehandler.h" // Access to hyperGridURL +#include "llworldmapmessage.h" // Access to sendNamedRegionRequest + // [RLVa:KB] - Checked: 2010-09-03 (RLVa-1.2.1b) #include "rlvhandler.h" // [/RLVa:KB] @@ -98,6 +102,46 @@ void LLTeleportHistory::goToItem(int idx) return; } + // [FIRE-35355] OpenSim global position is dependent on the Grid you are on + #ifdef OPENSIM + if (LLGridManager::getInstance()->isInOpenSim()) + { + if (mItems[mCurrentItem].mRegionID != mItems[idx].mRegionID) + { + LLSLURL slurl = mItems[idx].mSLURL; + std::string grid = slurl.getGrid(); + std::string current_grid = LFSimFeatureHandler::instance().hyperGridURL(); + std::string gatekeeper = LLGridManager::getInstance()->getGatekeeper(grid); + + // Requesting region information from the server is only required when changing grid + if (slurl.isValid() && grid != current_grid) + { + if (!gatekeeper.empty()) + { + slurl = LLSLURL(gatekeeper + ":" + slurl.getRegion(), slurl.getPosition(), true); + } + + if (mRequestedItem != -1) + { + return; // We already have a request in progress and don't want to spam the server + } + + mRequestedItem = idx; + + LLWorldMapMessage::getInstance()->sendNamedRegionRequest( + slurl.getRegion(), + boost::bind(&LLTeleportHistory::regionNameCallback, this, idx, _1, _2, _3, _4), + slurl.getSLURLString(), + true + ); + + return; // The teleport will occur in the callback with the correct global position + } + } + } + #endif + // + // Attempt to teleport to the requested item. gAgent.teleportViaLocation(mItems[idx].mGlobalPos); mRequestedItem = idx; @@ -210,6 +254,22 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos) mItems[mCurrentItem] = LLTeleportHistoryItem(RlvStrings::getString(RlvStringKeys::Hidden::Parcel), LLVector3d::zero); } // [/RLVa:KB] + + // [FIRE-35355] OpenSim global position is dependent on the Grid you are on, + // so we need to store the slurl so we can request the global position later + #ifdef OPENSIM + if (LLGridManager::getInstance()->isInOpenSim()) + { + auto regionp = gAgent.getRegion(); + if (regionp) + { + LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos); + LLSLURL slurl = LLSLURL(LFSimFeatureHandler::instance().hyperGridURL(), regionp->getName(), new_pos_local); + mItems[mCurrentItem].mSLURL = slurl; + } + } + #endif + // } //dump(); // LO - removing the dump from happening every time we TP. @@ -287,3 +347,35 @@ void LLTeleportHistory::dump() const LL_INFOS() << line.str() << LL_ENDL; } } + +// [FIRE-35355] Callback for OpenSim so we can teleport to the correct global position on another grid +void LLTeleportHistory::regionNameCallback(int idx, U64 region_handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport) +{ + if (region_handle) + { + // Sanity checks again just in case since time has passed since the request was made + if (idx < 0 || idx >= (int)mItems.size()) + { + LL_WARNS() << "Invalid teleport history index (" << idx << ") specified" << LL_ENDL; + return; + } + + if (idx == mCurrentItem) + { + LL_WARNS() << "Will not teleport to the same location." << LL_ENDL; + return; + } + + LLVector3d origin_pos = from_region_handle(region_handle); + LLVector3d global_pos(origin_pos + LLVector3d(slurl.getPosition())); + + // Attempt to teleport to the target grids region + gAgent.teleportViaLocation(global_pos); + } + else + { + LL_WARNS() << "Invalid teleport history region handle" << LL_ENDL; + onTeleportFailed(); + } +} +// diff --git a/indra/newview/llteleporthistory.h b/indra/newview/llteleporthistory.h index 6962f4afe3..5d705fe90d 100644 --- a/indra/newview/llteleporthistory.h +++ b/indra/newview/llteleporthistory.h @@ -35,6 +35,8 @@ #include #include "llteleporthistorystorage.h" +#include "llslurl.h" // Access to LLSLURL + /** * An item of the teleport history. @@ -47,8 +49,11 @@ public: LLTeleportHistoryItem() {} - LLTeleportHistoryItem(std::string title, LLVector3d global_pos) - : mTitle(title), mGlobalPos(global_pos) + // [FIRE-35355] OpenSim requires knowing the grid to teleport correctly if changing grids + //LLTeleportHistoryItem(std::string title, LLVector3d global_pos) + // : mTitle(title), mGlobalPos(global_pos) + LLTeleportHistoryItem(std::string title, LLVector3d global_pos, const LLSLURL& slurl = LLSLURL()) + : mTitle(title), mGlobalPos(global_pos), mSLURL(slurl) {} /** @@ -61,6 +66,7 @@ public: std::string mFullTitle; // human-readable location title including coordinates LLVector3d mGlobalPos; // global position LLUUID mRegionID; // region ID for getting the region info + LLSLURL mSLURL; // [FIRE-35355] slurl for the location required for OpenSim }; /** @@ -180,6 +186,10 @@ private: */ static std::string getCurrentLocationTitle(bool full, const LLVector3& local_pos_override); + // [FIRE-35355] Callback for OpenSim so we can teleport to the correct global position on another grid + void regionNameCallback(int idx, U64 handle, const LLSLURL& slurl, const LLUUID& snapshot_id, bool teleport); + // + /** * Actually, the teleport history. */ diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index b633dc4fed..bbcd832b14 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -2089,12 +2089,14 @@ LLPointer LLTextureCache::readFromFastCache(const LLUUID& id, S32& d // So a 1024x1024 texture with a dicard of 6 will become 32x32 and a 2048x2048 texture with a discard of 7 will become a 64x64 texture. if (discardlevel > MAX_DISCARD_LEVEL) { + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("FixBadDiscardLevel"); + S32 w = head[0]; // Get the current width from the header (16) S32 h = head[1]; // Get the current height from the header (16) // Expand the width and height by teh difference between the discard and MAX_DISCARD_LEVEL bit shifted to the left. (Expand power of 2 textures) - w <<= MAX_DISCARD_LEVEL - discardlevel; - h <<= MAX_DISCARD_LEVEL - discardlevel; + w <<= discardlevel - MAX_DISCARD_LEVEL; + h <<= discardlevel - MAX_DISCARD_LEVEL; // Set the discard level to the MAX_DISCARD_LEVEL discardlevel = MAX_DISCARD_LEVEL; diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index e50758ba2a..3614a6b754 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -224,6 +224,7 @@ LLVersionInfo::FSViewerMaturity LLVersionInfo::getFSViewerMaturity() const static const boost::regex is_alpha_channel("\\bAlpha(x64)?\\b"); static const boost::regex is_release_channel("\\bRelease(x64)?\\b"); static const boost::regex is_nightly_channel("\\bNightly(x64)?\\b"); + static const boost::regex is_streaming_channel("\\bStreaming\\b"); if (ll_regex_search(channel, is_release_channel)) { @@ -245,6 +246,10 @@ LLVersionInfo::FSViewerMaturity LLVersionInfo::getFSViewerMaturity() const { maturity = FSViewerMaturity::NIGHTLY_VIEWER; } + else if (ll_regex_search(channel, is_streaming_channel)) + { + maturity = FSViewerMaturity::STREAMING_VIEWER; + } else { maturity = FSViewerMaturity::UNOFFICIAL_VIEWER; diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h index d399dde814..5d1e90a654 100644 --- a/indra/newview/llversioninfo.h +++ b/indra/newview/llversioninfo.h @@ -119,6 +119,7 @@ public: BETA_VIEWER, NIGHTLY_VIEWER, RELEASE_VIEWER, + STREAMING_VIEWER, }; FSViewerMaturity getFSViewerMaturity() const; // diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 4fc57172d6..06f68e9407 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -225,6 +225,7 @@ #include "lggbeamcolormapfloater.h" #include "lggbeammapfloater.h" #include "llfloaterdisplayname.h" +#include "fsfloaterprimfeed.h" #include "llfloaterflickr.h" #include "llfloaterscriptrecover.h" #include "llfloatersearchreplace.h" @@ -630,6 +631,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("export_collada", "floater_export_collada.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("delete_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("flickr", "floater_flickr.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("primfeed", "floater_primfeed.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_asset_blacklist", "floater_fs_asset_blacklist.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_avatar_render_settings", "floater_fs_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_blocklist", "floater_fs_blocklist.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index c923c9e210..db120f592a 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2757,6 +2757,28 @@ class LLAdvancedCompressFileTest : public view_listener_t } }; +// Primfeed integration test functions (can be removed when the feature is stable) +/////////////////// +// PRIMFEED AUTH // +/////////////////// +#include "fsprimfeedauth.h" +class LLAdvancedPrimfeedAuth : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + FSPrimfeedAuth::initiateAuthRequest(); + return true; + } +}; +class LLAdvancedPrimfeedAuthReset : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + FSPrimfeedAuth::resetAuthStatus(); + return true; + } +}; +// ///////////////////////// // SHOW DEBUG SETTINGS // @@ -11882,6 +11904,19 @@ class LLWorldEnvSettings : public view_listener_t #endif // + // Redundant environment toggles revert to shared environment + LLSettingsSky::ptr_t sky = LLEnvironment::instance().getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL); + LLUUID skyid = (sky) ? sky->getAssetId() : LLUUID::null; + bool repeatedEnvTogglesShared = gSavedSettings.getBOOL("FSRepeatedEnvTogglesShared"); + + if(repeatedEnvTogglesShared && ((skyid == LLEnvironment::KNOWN_SKY_SUNRISE && event_name == "sunrise") || + (skyid == LLEnvironment::KNOWN_SKY_MIDDAY && event_name == "noon") || + (skyid == LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY && event_name == "legacy noon") || + (skyid == LLEnvironment::KNOWN_SKY_SUNSET && event_name == "sunset") || + (skyid == LLEnvironment::KNOWN_SKY_MIDNIGHT && event_name == "midnight"))) + event_name = "region"; + // + if (event_name == "sunrise") { // FIRE-29926 - allow manually selected environments to have a user defined transition time. @@ -12906,6 +12941,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); view_listener_t::addMenu(new LLAdvancedCompressFileTest(), "Advanced.CompressFileTest"); + view_listener_t::addMenu(new LLAdvancedPrimfeedAuth(), "Advanced.PrimfeedAuth"); + view_listener_t::addMenu(new LLAdvancedPrimfeedAuthReset(), "Advanced.PrimfeedAuthReset"); view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3e43434eb2..213ec602a5 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -6687,6 +6687,7 @@ void process_alert_core(const std::string& message, bool modal) if (text.substr(0, restart_cancelled.length()) == restart_cancelled) { LLFloaterRegionRestarting::close(); + fs_report_region_restart_to_channel(-1); // Announce region restart to a defined chat channel } std::string new_msg =LLNotifications::instance().getGlobalString(text); @@ -8755,7 +8756,14 @@ void fs_report_region_restart_to_channel(S32 seconds) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_ChatData); - msg->addStringFast(_PREHASH_Message, "region_restart_in:" + llformat("%d", seconds)); + if(seconds >= 0) + { + msg->addStringFast(_PREHASH_Message, "region_restart_in:" + llformat("%d", seconds)); + } + else // Input is a negative number + { + msg->addStringFast(_PREHASH_Message, "region_restart_cancelled"); + } msg->addU8Fast(_PREHASH_Type, CHAT_TYPE_WHISPER); msg->addS32("Channel", channel); gAgent.sendReliableMessage(); diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 45af5f228d..e170d8fa19 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -835,7 +835,7 @@ void LLViewerObjectList::setAllObjectDefaultTextures(U32 nChannel, bool fShowDef } } // [/SL:KB] -// [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer +// [FIRE-35081] Blurry prims not changing with graphics settings //void LLViewerObjectList::updateApparentAngles(LLAgent &agent) // Added time limit on processing of objects as they affect the texture system (They also calcuate mMaxVirtualSize and mPixelArea) void LLViewerObjectList::updateApparentAngles(LLAgent &agent, F32 max_time) @@ -845,7 +845,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent, F32 max_time) LLViewerObject *objectp; S32 num_updates, max_value; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Remove the old code as it worked on fixed number of updates (Total # of Object / 128) per frame // and some objects had nothing to do while others were avatars or volumes and could t /* diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index fe13d3a4ae..c4a8026f93 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -89,7 +89,7 @@ public: void processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type, bool compressed=false); void processCompressedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type); void processCachedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //void updateApparentAngles(LLAgent &agent); // Added time limit on processing of objects as they affect the texture system void updateApparentAngles(LLAgent &agent, F32 max_time); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index d2e8826e10..c214507a46 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -121,6 +121,7 @@ namespace void newRegionEntry(LLViewerRegion& region) { + LL_PROFILE_ZONE_SCOPED; // improve instrumentation LL_INFOS("LLViewerRegion") << "Entering region [" << region.getName() << "]" << LL_ENDL; gDebugInfo["CurrentRegion"] = region.getName(); LLAppViewer::instance()->writeDebugInfo(); @@ -3983,11 +3984,14 @@ bool LLViewerRegion::bakesOnMeshEnabled() const mSimulatorFeatures["BakesOnMeshEnabled"].asBoolean()); } +// FIRE-35602 etc - Mesh not appearing after TP/login (opensim only) +#ifdef OPENSIM bool LLViewerRegion::meshRezEnabled() const { - return (mSimulatorFeatures.has("MeshRezEnabled") && - mSimulatorFeatures["MeshRezEnabled"].asBoolean()); + return (mSimulatorFeatures.has("MeshRezEnabled") && mSimulatorFeatures["MeshRezEnabled"].asBoolean()); } +#endif +// bool LLViewerRegion::dynamicPathfindingEnabled() const { diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 07388518f3..119647ecbf 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -355,8 +355,11 @@ public: U8 getCentralBakeVersion() { return mCentralBakeVersion; } void getInfo(LLSD& info); - +// FIRE-35602 etc - Mesh not appearing after TP/login (opensim only) +#ifdef OPENSIM bool meshRezEnabled() const; +#endif // OPENSIM +// bool meshUploadEnabled() const; bool bakesOnMeshEnabled() const; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index c4e80c97ea..045a628b39 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -779,7 +779,7 @@ void LLViewerTexture::setBoostLevel(S32 level) mBoostLevel = level; if(mBoostLevel != LLViewerTexture::BOOST_NONE && mBoostLevel != LLViewerTexture::BOOST_SELECTED && - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Added the new boost levels mBoostLevel != LLViewerTexture::BOOST_GRASS && mBoostLevel != LLViewerTexture::BOOST_LIGHT && @@ -796,7 +796,7 @@ void LLViewerTexture::setBoostLevel(S32 level) if (mBoostLevel >= LLViewerTexture::BOOST_HIGH) { mMaxVirtualSize = 2048.f * 2048.f; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Add additional for the important to camera and in frustum static LLCachedControl texture_camera_boost(gSavedSettings, "TextureCameraBoost", 7.f); mMaxVirtualSize = mMaxVirtualSize + (mMaxVirtualSize * 1.0f * texture_camera_boost); @@ -1209,7 +1209,7 @@ void LLViewerFetchedTexture::init(bool firstinit) mKeptSavedRawImageTime = 0.f; mLastCallBackActiveTime = 0.f; mForceCallbackFetch = false; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings mCloseToCamera = 1.0f; // Store if the camera is close to the camera (0.0f or 1.0f) // [FIRE-35081] @@ -3085,13 +3085,13 @@ void LLViewerLODTexture::processTextureStats() else if (mBoostLevel < LLGLTexture::BOOST_HIGH && mMaxVirtualSize <= 10.f) { // If the image has not been significantly visible in a while, we don't want it - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1)); // Off screen textures at 6 would not downscale. mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL)); // [FIRE-35081] mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S32)mLoadedCallbackDesiredDiscardLevel); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Add scale down here as the textures off screen were not getting scaled down properly S32 current_discard = getDiscardLevel(); if (mBoostLevel < LLGLTexture::BOOST_AVATAR_BAKED) @@ -3110,7 +3110,7 @@ void LLViewerLODTexture::processTextureStats() } else { - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings /* //static const F64 log_2 = log(2.0); static const F64 log_4 = log(4.0); @@ -3455,7 +3455,7 @@ void LLViewerMediaTexture::initVirtualSize() { return; } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Add camera importance to the media textures as well static LLCachedControl texture_camera_boost(gSavedSettings, "TextureCameraBoost", 7.f); F32 vsize = 0.0f; @@ -3463,7 +3463,7 @@ void LLViewerMediaTexture::initVirtualSize() findFaces(); for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) { - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //addTextureStats((*iter)->getVirtualSize()); // Add camera importance to the media textures as well vsize = (*iter)->getVirtualSize(); @@ -3531,7 +3531,7 @@ void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) } // [/SL:KB] - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Try to set the boost level to MEDIA to try to force the media to high quality tex->setBoostLevel(LLViewerTexture::MEDIA); // [FIRE-35081] @@ -3776,7 +3776,7 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() { addTextureStats(0.f, false);//reset } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings static LLCachedControl texture_camera_boost(gSavedSettings, "TextureCameraBoost", 7.f); F32 vsize = 0.0f; // [FIRE-35081] @@ -3790,7 +3790,7 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() LLFace* facep = mFaceList[ch][i]; if(facep->getDrawable()->isRecentlyVisible()) { - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //addTextureStats(facep->getVirtualSize()); // Add the importance to camera and close to camera to the media texture vsize = facep->getVirtualSize(); @@ -3814,7 +3814,7 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() LLFace* facep = *iter; if(facep->getDrawable()->isRecentlyVisible()) { - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //addTextureStats(facep->getVirtualSize()); // Add the importance to camera and close to camera to the media texture vsize = facep->getVirtualSize(); diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index c39c1a212d..d7e2ae3b72 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -437,7 +437,7 @@ public: void setInFastCacheList(bool in_list) { mInFastCacheList = in_list; } bool isInFastCacheList() { return mInFastCacheList; } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings F32 getCloseToCamera() const {return mCloseToCamera ;} // Get close to camera value void setCloseToCamera(F32 value) {mCloseToCamera = value ;} // Set the close to camera value (0.0f or 1.0f) // [FIRE-35081] @@ -543,7 +543,7 @@ protected: bool mForSculpt ; //a flag if the texture is used as sculpt data. bool mIsFetched ; //is loaded from remote or from cache, not generated locally. - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings F32 mCloseToCamera; // Float (0.0f or 1.0f) to indicate if the texture is close to the camera // [FIRE-35081] diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 362f2f61a2..f2de57f14c 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -372,7 +372,7 @@ void LLViewerTextureList::shutdown() mInitialized = false ; //prevent loading textures again. } -// [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer +// [FIRE-35081] Blurry prims not changing with graphics settings // static // Allows the menu to call the dump method of the texture list void LLViewerTextureList::dumpTexturelist() @@ -385,12 +385,13 @@ void LLViewerTextureList::dump() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings S32 texture_count = 0; S32 textures_close_to_camera = 0; std::array image_counts{0}; // Double the size for higher discards from textures < 1024 (2048 can make a 7 and 4096 could make an 8) std::array size_counts{0}; // Track the 12 possible sizes (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048) std::array discard_counts{0}; // Also need to an 1 additional as -1 is a valid discard level (not loaded by reported as a 1x1 texture) + std::array fullsize_discard_counts{0}; // Also need to an 1 additional as -1 is a valid discard level (not loaded by reported as a 1x1 texture) std::array boost_counts{0}; // Track the # of textures at boost levels by 12 possible sizes // Don't Init the buffers with 0's like it's the the 1980's... @@ -398,36 +399,30 @@ void LLViewerTextureList::dump() for (image_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) { LLViewerFetchedTexture* image = *it; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer - std::string face_counts = ""; - std::string volume_counts = ""; - for (S32 index = 0; index < LLRender::NUM_TEXTURE_CHANNELS; index++) - { - face_counts += std::to_string(image->getNumFaces(index)) + " "; - } - - for (S32 index = 0; index < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; index++) - { - volume_counts += std::to_string(image->getNumVolumes(index)) + " "; - } - // [FIRE-35081] - LL_INFOS() << "priority " << image->getMaxVirtualSize() << " boost " << image->getBoostLevel() << " size " << image->getWidth() << "x" << image->getHeight() << " discard " << image->getDiscardLevel() << " desired " << image->getDesiredDiscardLevel() - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings << " close to camera " << (image->getCloseToCamera() > 0.0f ? "Y" : "N") // Display the close to camera flag << " FFType " << fttype_to_string(image->getFTType()) // Display the FFType of the camera << " Type " << (S32)image->getType() // Display the type of the image (LOCAL_TEXTURE = 0, MEDIA_TEXTURE = 1, DYNAMIC_TEXTURE = 2, FETCHED_TEXTURE = 3,LOD_TEXTURE = 4) << " Sculpted " << (image->forSculpt() ? "Y" : "N") - << " # of Faces " << face_counts - << " # of Volumes " << volume_counts + << " # of Faces "; + for (S32 index = 0; index < LLRender::NUM_TEXTURE_CHANNELS; index++) + { + LL_CONT << image->getNumFaces(index) << " "; + } + LL_CONT << " # of Volumes "; + for (S32 index = 0; index < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; index++) + { + LL_CONT << image->getNumVolumes(index) << " "; + } // [FIRE-35081] - << " http://asset.siva.lindenlab.com/" << image->getID() << ".texture" + LL_CONT << " http://asset.siva.lindenlab.com/" << image->getID() << ".texture" << LL_ENDL; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings image_counts[(image->getDiscardLevel() + 1)] += 1; // Need to add +1 to make up for -1 being a possible value S32 x_index = (S32)log2(image->getWidth()); // Convert the width into a 0 based index by taking the Log2 of the size to get the exponent of the size. (1 = 2^0, 2 = 2^1, 4 = 2^2...) S32 y_index = (S32)log2(image->getHeight()); // Convert the height into a 0 based index by taking the Log2 of the size to get the exponent of the size. (1 = 2^0, 2 = 2^1, 4 = 2^2...) @@ -436,11 +431,15 @@ void LLViewerTextureList::dump() S32 max_dimension = (y_index > x_index ? y_index : x_index); discard_counts[(image->getDiscardLevel() + 1) + max_dimension * (MAX_DISCARD_LEVEL * 2 + 2)] += 1; boost_counts[image->getBoostLevel() + max_dimension * (LLViewerTexture::BOOST_MAX_LEVEL)] += 1; + S32 full_x_index = (S32)log2(image->getFullWidth()); + S32 full_y_index = (S32)log2(image->getFullHeight()); + S32 full_max_dimension = (full_y_index > full_x_index ? full_y_index : full_x_index); + fullsize_discard_counts[(image->getDiscardLevel() + 1) + full_max_dimension * (MAX_DISCARD_LEVEL * 2 + 2)] += 1; texture_count++; textures_close_to_camera += S32(image->getCloseToCamera()); // [FIRE-35081] } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Add overal texture totals LL_INFOS() << "Texture Stats: Textures in Close to Camera " << textures_close_to_camera << " of " << texture_count << " : " << LL_ENDL; @@ -450,150 +449,108 @@ void LLViewerTextureList::dump() LL_INFOS() << " Discard Level: " << (index - 1) << " Number of Textures: " << image_counts[index] << LL_ENDL; } - // Create a header that for the Sizes - std::string header = "Size "; - for (S32 x = 0; x < 12; x++) - { - std::string newValue = std::to_string((S32)pow(2, x)); - header += newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) - { - header += " "; - } - } - // Create a line to break up the header from the content of the table - std::string header_break = ""; - for (S32 x = 0; x < header.length(); x++) - { - header_break += "-"; - } + std::string header_break(13 * 8, '-'); + LL_INFOS() << "Size vs Size" << LL_ENDL; LL_INFOS() << header_break << LL_ENDL; - LL_INFOS() << header << LL_ENDL; // Size vs Size counts header + // Create a header that for the Sizes + LL_INFOS() << std::setw(8) << "Size"; + for (S32 x = 1; x <= 2048; x <<= 1) + { + LL_CONT << std::setw(8) << x; + } + LL_CONT << LL_ENDL; LL_INFOS() << header_break << LL_ENDL; // Y Axis is the size of the height of the texture for (S32 y = 0; y < 12; y++) { - std::string newValue = std::to_string((S32)pow(2, y)); - std::string size_count_string = "" + newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) - { - size_count_string += " "; - } - + LL_INFOS() << std::setw(8) << (1 << y); //X Axis is the size of the width of the texture for (S32 x = 0; x < 12; x++) { - newValue = std::to_string(size_counts[x + y * 12]); - size_count_string += newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) - { - size_count_string += " "; - } - } - LL_INFOS() << size_count_string << LL_ENDL; - } - LL_INFOS() << header_break << LL_ENDL; - LL_INFOS() << header << LL_ENDL; // Size vs Size counts footer - LL_INFOS() << header_break << LL_ENDL; + LL_CONT << std::setw(8) << size_counts[x + y * 12]; - LL_INFOS() << "" << LL_ENDL; + } + LL_CONT << LL_ENDL; + } + LL_INFOS() << LL_ENDL; // This is the Discard Level Vs Size counts table - header = "Discard: "; + LL_INFOS() << "Discard Level Vs Size" << LL_ENDL; + LL_INFOS() << header_break << LL_ENDL; + LL_INFOS() << std::setw(8) << "Discard"; for (S32 x = 0; x < MAX_DISCARD_LEVEL * 2 + 2; x++) { - std::string newValue = std::to_string(x - 1); - header += newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) - { - header += " "; - } + LL_CONT << std::setw(8) << (x - 1); } - - header_break = ""; - for (S32 x = 0; x < header.length(); x++) - { - header_break += "-"; - } - - LL_INFOS() << header_break << LL_ENDL; - LL_INFOS() << header << LL_ENDL; // Discard Level Vs Size counts header + LL_CONT << LL_ENDL; LL_INFOS() << header_break << LL_ENDL; // Y Axis is the current possible max dimension of the textures (X or Y, which ever is larger is used) for (S32 y = 0; y < 12; y++) { - std::string newValue = std::to_string((S32)pow(2, y)); - std::string discard_count_string = "" + newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) - { - discard_count_string += " "; - } + LL_INFOS() << std::setw(8) << (1 << y); // X Axis is the discard level starging from -1 up to 10 (2 x MAX_DISCARD_LEVEL + 1 (for negative number) + 1 additional for the fact that the last value actuauly used on not < but <=) for (S32 x = 0; x < (MAX_DISCARD_LEVEL * 2 + 2); x++) { - std::string newValue = std::to_string(discard_counts[x + y * (MAX_DISCARD_LEVEL * 2 + 2)]); - discard_count_string += newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) - { - discard_count_string += " "; - } + LL_CONT << std::setw(8) << discard_counts[x + y * (MAX_DISCARD_LEVEL * 2 + 2)]; } - LL_INFOS() << discard_count_string << LL_ENDL; + LL_CONT << LL_ENDL; } - LL_INFOS() << header_break << LL_ENDL; - LL_INFOS() << header << LL_ENDL; // Discard Level Vs Size counts footer - LL_INFOS() << header_break << LL_ENDL; + LL_INFOS() << LL_ENDL; + - // This is the Boost Level Vs Size counts table - header = "Boost: "; - for (S32 x = 0; x < LLViewerTexture::BOOST_MAX_LEVEL; x++) + // This is the Discard Level Vs Full Size counts table + LL_INFOS() << "Discard Level Vs Full Size" << LL_ENDL; + LL_INFOS() << header_break << LL_ENDL; + LL_INFOS() << std::setw(8) << "Discard"; + for (S32 x = 0; x < MAX_DISCARD_LEVEL * 2 + 2; x++) { - std::string newValue = std::to_string(x); - header += newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) - { - header += " "; - } + LL_CONT << std::setw(8) << (x - 1); } - - header_break = ""; - for (S32 x = 0; x < header.length(); x++) - { - header_break += "-"; - } - - LL_INFOS() << header_break << LL_ENDL; - LL_INFOS() << header << LL_ENDL; // Boost Level Vs Size counts header + LL_CONT << LL_ENDL; LL_INFOS() << header_break << LL_ENDL; // Y Axis is the current possible max dimension of the textures (X or Y, which ever is larger is used) for (S32 y = 0; y < 12; y++) { - std::string newValue = std::to_string((S32)pow(2, y)); - std::string boost_count_string = "" + newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) + LL_INFOS() << std::setw(8) << (1 << y); + // X Axis is the discard level starging from -1 up to 10 (2 x MAX_DISCARD_LEVEL + 1 (for negative number) + 1 additional for the fact that the last value actuauly used on not < but <=) + for (S32 x = 0; x < (MAX_DISCARD_LEVEL * 2 + 2); x++) { - boost_count_string += " "; + LL_CONT << std::setw(8) << fullsize_discard_counts[x + y * (MAX_DISCARD_LEVEL * 2 + 2)]; } + LL_CONT << LL_ENDL; + } + LL_INFOS() << LL_ENDL; + + + // This is the Boost Level Vs Size counts table + LL_INFOS() << "Boost Level Vs Size" << LL_ENDL; + header_break.append((LLViewerTexture::BOOST_MAX_LEVEL * 8) - (12 * 8), '-'); + LL_INFOS() << header_break << LL_ENDL; + LL_INFOS() << std::setw(8) << "Discard"; + for (S32 x = 0; x < LLViewerTexture::BOOST_MAX_LEVEL; x++) + { + LL_CONT << std::setw(8) << x; + } + LL_CONT << LL_ENDL; + LL_INFOS() << header_break << LL_ENDL; + + // Y Axis is the current possible max dimension of the textures (X or Y, which ever is larger is used) + for (S32 y = 0; y < 12; y++) + { + LL_INFOS() << std::setw(8) << (1 << y); // X Axis is the boost level starging from BOOST_NONE up to BOOST_MAX_LEVEL for (S32 x = 0; x < (LLViewerTexture::BOOST_MAX_LEVEL); x++) { - std::string newValue = std::to_string(boost_counts[x + y * (LLViewerTexture::BOOST_MAX_LEVEL)]); - boost_count_string += newValue; - for (S32 tab = 0; tab <= 8 - newValue.length(); tab++) - { - boost_count_string += " "; - } + LL_CONT << std::setw(8) << boost_counts[x + y * (LLViewerTexture::BOOST_MAX_LEVEL)]; } - LL_INFOS() << boost_count_string << LL_ENDL; + LL_CONT << LL_ENDL; } - LL_INFOS() << header_break << LL_ENDL; - LL_INFOS() << header << LL_ENDL; // Boost Level Vs Size counts footer - LL_INFOS() << header_break << LL_ENDL; + LL_INFOS() << LL_ENDL; // [FIRE-35081] } @@ -851,6 +808,14 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, imagep->setExplicitFormat(internal_format, primary_format); } + // [FIRE-35428] - Mega prim issue - fix compressed sculpted textures + // Sculpted textures use the RGBA data for coodinates, so any compression can cause artifacts. + if (boost_priority == LLViewerFetchedTexture::BOOST_SCULPTED) + { + // Disable the compression of BOOST_SCULPTED textures + if (imagep->getGLTexture())imagep->getGLTexture()->setAllowCompression(false); + } + // [FIRE-35428] addImage(imagep, get_element_type(boost_priority)); if (boost_priority != 0) @@ -878,7 +843,11 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, } // Keep Fast Cache option - if(fast_cache_fetching_enabled) + // [FIRE-35428] - Mega prim issue - fix compressed sculpted textures + //if(fast_cache_fetching_enabled) + // If the texture is Sculpted, don't allow it to be added to fast cache as it can affect the texture. + if(fast_cache_fetching_enabled && boost_priority != LLViewerFetchedTexture::BOOST_SCULPTED) + // [FIRE-35428] { mFastCacheList.insert(imagep); imagep->setInFastCacheList(true); @@ -1138,7 +1107,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag F32 bias = llclamp(max_discard - 2.f, 1.f, LLViewerTexture::sDesiredDiscardBias); // convert bias into a vsize scaler - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //bias = (F32) llroundf(powf(4, bias - 1.f)); // Pre-divide the bias so you can just use multiply in the loop bias = (F32) 1.0f / llroundf(powf(4, bias - 1.f)); @@ -1180,7 +1149,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag if (face && face->getViewerObject()) { ++face_count; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // No longer needed as we no longer re-calculate the face's virtual texture size, we use it directly from the face //F32 radius; //F32 cos_angle_to_view_dir; @@ -1199,7 +1168,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag } // Also moved allocation outside the loop - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //F32 vsize = face->getPixelArea(); //on_screen |= face->mInFrustum; @@ -1214,7 +1183,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag animated += S64(face->hasMedia()); // Add has media for both local and parcel media animated += S64(imagep->hasParcelMedia()); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer (It is) + // [FIRE-35081] Blurry prims not changing with graphics settings (It is) /* // Scale desired texture resolution higher or lower depending on texture scale // @@ -1268,14 +1237,14 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag vsize = vsize + (vsize * face->mCloseToCamera * texture_camera_boost); // Update the max on screen vsize based upon the on screen vsize close_to_camera += face->mCloseToCamera; - LL_DEBUGS() << face->getViewerObject()->getID() << " TID " << imagep->getID() << " #F " << imagep->getNumFaces(i) << " OS Vsize: " << vsize << " Vsize: " << (vsize * bias) << " CTC: " << face->mCloseToCamera << " Channel " << i << " Face Index " << fi << LL_ENDL; + // LL_DEBUGS() << face->getViewerObject()->getID() << " TID " << imagep->getID() << " #F " << imagep->getNumFaces(i) << " OS Vsize: " << vsize << " Vsize: " << (vsize * bias) << " CTC: " << face->mCloseToCamera << " Channel " << i << " Face Index " << fi << LL_ENDL; max_on_screen_vsize = llmax(max_on_screen_vsize, vsize); max_vsize = llmax(max_vsize, vsize * bias); // [FIRE-35081] } } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //if (max_vsize >= LLViewerFetchedTexture::sMaxVirtualSize // && (on_screen || LLViewerTexture::sDesiredDiscardBias <= BIAS_TRS_ON_SCREEN)) //{ @@ -1284,7 +1253,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag // } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Replaced all the checks for this bool to be only in this 1 place instead of in the loop. // If the on screen counter is greater then 0, then there was at least 1 on screen texture on_screen = bool(on_screen_count); @@ -1312,7 +1281,7 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag } } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //imagep->addTextureStats(max_vsize); // New logic block for the bias system // Then depending on the type of texture, the higher resolution on_screen_max_vsize is applied. @@ -1439,7 +1408,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) mCreateTextureList.pop(); if (imagep->hasGLTexture() && imagep->getDiscardLevel() < imagep->getDesiredDiscardLevel() && - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //(imagep->getDesiredDiscardLevel() <= MAX_DISCARD_LEVEL)) // Add additional restrictions on scaling down (only BOOST_NONE LOD Textures (Also skip media) (imagep->getDesiredDiscardLevel() <= MAX_DISCARD_LEVEL) && imagep->getBoostLevel() == LLViewerTexture::BOOST_NONE && imagep->getType() == LLViewerTexture::LOD_TEXTURE && !imagep->hasParcelMedia() && !imagep->isViewerMediaTexture()) diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index c8e9693c58..e2f9c15a5a 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -111,7 +111,7 @@ public: static void receiveImageHeader(LLMessageSystem *msg, void **user_data); static void receiveImagePacket(LLMessageSystem *msg, void **user_data); // - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings static void dumpTexturelist(); // Added code to handle dumping texture information // [FIRE-35081] diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 5937d76e4d..00cc7aa702 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -5939,8 +5939,15 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save filepath = sSnapshotDir; filepath += gDirUtilp->getDirDelimiter(); filepath += sSnapshotBaseName; - filepath += now.toLocalDateString("_%Y-%m-%d_%H%M%S"); - filepath += llformat("%.2d", i); +// FIRE-35391 - Restore ability for snapshots saving with simple index number +// filepath += now.toLocalDateString("_%Y-%m-%d_%H%M%S"); +// filepath += llformat("%.2d", i); + if (gSavedSettings.getBOOL("FSSnapshotLocalNamesWithTimestamps")) + { + filepath += now.toLocalDateString("_%Y-%m-%d_%H%M%S"); + } + filepath += llformat("_%.3d", i); +// filepath += extension; llstat stat_info; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 156ddf6d37..eff5096ad6 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2974,7 +2974,7 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU LL_DEBUGS("Avatar") << avString() << "get old-bake image from host " << uuid << LL_ENDL; LLHost host = getObjectHost(); result = LLViewerTextureManager::getFetchedTexture( - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //uuid, FTT_HOST_BAKE, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); uuid, FTT_HOST_BAKE, true, LLGLTexture::BOOST_AVATAR_BAKED, LLViewerTexture::LOD_TEXTURE, 0, 0, host); // [FIRE-35081] @@ -7286,69 +7286,44 @@ const LLUUID& LLVOAvatar::getID() const //----------------------------------------------------------------------------- // RN: avatar joints are multi-rooted to include screen-based attachments // virtual -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -//LLJoint *LLVOAvatar::getJoint( const std::string &name ) -LLJoint *LLVOAvatar::getJoint( const JointKey &name ) -// +// Joint-lookup improvements +//LLJoint *LLVOAvatar::getJoint(const std::string &name) +LLJoint *LLVOAvatar::getJoint(std::string_view name) { LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup + // Joint-lookup improvements //joint_map_t::iterator iter = mJointMap.find( name ); - - //LLJoint* jointp = NULL; - - //if( iter == mJointMap.end() || iter->second == NULL ) - //{ //search for joint and cache found joint in lookup table - // if (mJointAliasMap.empty()) - // { - // getJointAliases(); - // } - // joint_alias_map_t::const_iterator alias_iter = mJointAliasMap.find(name); - // std::string canonical_name; - // if (alias_iter != mJointAliasMap.end()) - // { - // canonical_name = alias_iter->second; - // } - // else - // { - // canonical_name = name; - // } - // jointp = mRoot->findJoint(canonical_name); - // mJointMap[name] = jointp; - //} - //else - //{ //return cached pointer - // jointp = iter->second; - //} - - joint_map_t::iterator iter = mJointMap.find( name.mKey ); + joint_map_t::iterator iter = mJointMap.find(name.data()); LLJoint* jointp = NULL; - if (iter == mJointMap.end() || iter->second == NULL) - { //search for joint and cache found joint in lookup table - if (mJointAliasMap.empty()) - { - getJointAliases(); - } - joint_alias_map_t::const_iterator alias_iter = mJointAliasMap.find(name.mName); - std::string canonical_name; - if (alias_iter != mJointAliasMap.end()) - { - canonical_name = alias_iter->second; - } - else - { - canonical_name = name.mName; - } - jointp = mRoot->findJoint(canonical_name); - mJointMap[name.mKey] = jointp; + if( iter == mJointMap.end() || iter->second == NULL ) + { //search for joint and cache found joint in lookup table + if (mJointAliasMap.empty()) + { + getJointAliases(); + } + // Joint-lookup improvements + //joint_alias_map_t::const_iterator alias_iter = mJointAliasMap.find(name); + joint_alias_map_t::const_iterator alias_iter = mJointAliasMap.find(std::string(name)); + std::string canonical_name; + if (alias_iter != mJointAliasMap.end()) + { + canonical_name = alias_iter->second; + } + else + { + canonical_name = name; + } + jointp = mRoot->findJoint(canonical_name); + // Joint-lookup improvements + //mJointMap[name] = jointp; + mJointMap[std::string(name)] = jointp; } else - { //return cached pointer - jointp = iter->second; + { //return cached pointer + jointp = iter->second; } -// #ifndef LL_RELEASE_FOR_DOWNLOAD if (jointp && jointp->getName()!="mScreen" && jointp->getName()!="mRoot") @@ -7389,6 +7364,16 @@ LLJoint *LLVOAvatar::getJoint( S32 joint_num ) return pJoint; } +void LLVOAvatar::initAllJoints() +{ + getJointAliases(); + for (auto& alias : mJointAliasMap) + { + mJointMap[alias.first] = mRoot->findJoint(alias.second); + } + // ignore mScreen and mRoot +} + //----------------------------------------------------------------------------- // getRiggedMeshID // @@ -7717,11 +7702,7 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// std::string lookingForJoint = pSkinData->mJointNames[ i ].c_str(); - JointKey lookingForJoint = pSkinData->mJointNames[ i ]; -// - + std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); LLJoint* pJoint = getJoint( lookingForJoint ); if (pJoint) { @@ -7734,10 +7715,7 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// if( lookingForJoint == "mPelvis" ) - if( lookingForJoint.mName == "mPelvis" ) -// + if( lookingForJoint == "mPelvis" ) { pelvisGotSet = true; } @@ -7928,10 +7906,7 @@ void LLVOAvatar::removeAttachmentOverridesForObject(LLViewerObject *vo) //----------------------------------------------------------------------------- void LLVOAvatar::removeAttachmentOverridesForObject(const LLUUID& mesh_id) { -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// LLJoint* pJointPelvis = getJoint( "mPelvis" ); - LLJoint* pJointPelvis = getJoint( JointKey::construct( "mPelvis" ) ); -// + LLJoint* pJointPelvis = getJoint( "mPelvis" ); const std::string av_string = avString(); for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) @@ -8119,10 +8094,7 @@ void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints) attachment->setName(info->mName); -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// LLJoint *parent_joint = getJoint(info->mJointName); - LLJoint *parent_joint = getJoint( JointKey::construct( info->mJointName ) ); -// + LLJoint *parent_joint = getJoint(info->mJointName); if (!parent_joint) { @@ -11018,7 +10990,7 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte //LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL; LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL; setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); //Texture will use baked textures, so it should also use that for the boost. LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, true, LLGLTexture::BOOST_AVATAR_BAKED, LLViewerTexture::LOD_TEXTURE)); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 90ab7c527a..f6205dca12 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -204,12 +204,11 @@ public: void startDefaultMotions(); void dumpAnimationState(); -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //virtual LLJoint* getJoint( const std::string &name ); - virtual LLJoint* getJoint( const JointKey &name ); - LLJoint* getJoint( const std::string &name ) { return getJoint( JointKey::construct( name ) ); } -// + // Joint-lookup improvements + //virtual LLJoint* getJoint(const std::string &name); + virtual LLJoint* getJoint(std::string_view name); LLJoint* getJoint(S32 num); + void initAllJoints(); //if you KNOW joint_num is a valid animated joint index, use getSkeletonJoint for efficiency inline LLJoint* getSkeletonJoint(S32 joint_num) { return mSkeleton[joint_num]; } diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index bd0405e37f..9dae1846ca 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -272,6 +272,8 @@ void LLVOAvatarSelf::initInstance() doPeriodically(check_for_unsupported_baked_appearance, 120.0); doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); + initAllJoints(); // mesh thread uses LLVOAvatarSelf as a joint source + mInitFlags |= 1<<2; } @@ -1027,27 +1029,22 @@ void LLVOAvatarSelf::idleUpdate(LLAgent &agent, const F64 &time) } // virtual -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -//LLJoint *LLVOAvatarSelf::getJoint( const std::string &name ) -LLJoint *LLVOAvatarSelf::getJoint( const JointKey &name ) -// +// Joint-lookup improvements +//LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) +LLJoint* LLVOAvatarSelf::getJoint(std::string_view name) { std::lock_guard lock(mJointMapMutex); LLJoint *jointp = NULL; jointp = LLVOAvatar::getJoint(name); if (!jointp && mScreenp) { - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup - //jointp = mScreenp->findJoint(name); - jointp = mScreenp->findJoint(name.mName); - // + jointp = mScreenp->findJoint(name); if (jointp) { - // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup + // Joint-lookup improvements //mJointMap[name] = jointp; - mJointMap[name.mKey] = jointp; - // - } + mJointMap[std::string(name)] = jointp; + } } if (jointp && jointp != mScreenp && jointp != mRoot) { diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index de8a435be9..688891eb68 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -91,10 +91,9 @@ public: /*virtual*/ void stopMotionFromSource(const LLUUID& source_id); /*virtual*/ void requestStopMotion(LLMotion* motion); -// Query by JointKey rather than just a string, the key can be a U32 index for faster lookup -// /*virtual*/ LLJoint* getJoint( const std::string &name ); - /*virtual*/ LLJoint* getJoint( const JointKey &name ); -// + // Joint-lookup improvements +// /*virtual*/ LLJoint* getJoint(const std::string &name); + /*virtual*/ LLJoint* getJoint(std::string_view name); /*virtual*/ void renderJoints(); diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index ccdc38a332..3551492a77 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -99,7 +99,7 @@ void LLVOGrass::updateSpecies() SpeciesMap::const_iterator it = sSpeciesTable.begin(); mSpecies = (*it).first; } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //setTEImage(0, LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); // Added new boost Grass as it forces a fixed size on updates setTEImage(0, LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, FTT_DEFAULT, true, LLGLTexture::BOOST_GRASS, LLViewerTexture::LOD_TEXTURE)); diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 954faa5572..deaa952f0a 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -330,7 +330,7 @@ U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys, // Load Species-Specific data // static const S32 MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = 32 ; //frames. - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); // Set boost level for Tree as it overrides the normal texture sizes mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, FTT_DEFAULT, true, LLGLTexture::BOOST_TREE, LLViewerTexture::LOD_TEXTURE); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 6a3be5300f..957b1e5b06 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -742,7 +742,7 @@ void LLVOVolume::animateTextures() { LLFace* facep = mDrawable->getFace(i); if (!facep) continue; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Removed check for turning off animations //if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue; // [FIRE-35081] @@ -770,7 +770,7 @@ void LLVOVolume::animateTextures() if (!facep->mTextureMatrix) { facep->mTextureMatrix = new LLMatrix4(); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Removed check for turning off animations //if (facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) // [FIRE-35081] @@ -926,7 +926,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) F32 min_vsize=999999999.f, max_vsize=0.f; LLViewerCamera* camera = LLViewerCamera::getInstance(); std::stringstream debug_text; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Use this flag to indicate that there was a legit change to 0.0 for the mPixelArea (All faces off screen) bool changed = false; // [FIRE-35081] @@ -978,7 +978,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) mPixelArea = llmax(mPixelArea, face->getPixelArea()); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // If the new area is changed from the old area, then accept it. if (mPixelArea != old_area) { @@ -1073,7 +1073,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) { LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); LLUUID id = params->getLightTexture(); - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Light textures should be treaded not the same as normal LOD textures mLightTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_LIGHT); // [FIRE-35081] @@ -1126,7 +1126,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) setDebugText(output); } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings //if (mPixelArea == 0) // If there is a legit change to 0.0, don't dismiss it. if (mPixelArea == 0 && !changed) @@ -2671,10 +2671,11 @@ S32 LLVOVolume::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID) S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) { S32 res = LLViewerObject::setTEMaterialParams(te, pMaterialParams); - - LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterialParams) ? pMaterialParams->asLLSD() : LLSD("null")) << " res " << res - << ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast(this), te) ? " selected" : " not selected" ) - << LL_ENDL; + // Remove debug logging that is more expensive than the call itself even when disabled + // LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterialParams) ? pMaterialParams->asLLSD() : LLSD("null")) << " res " << res + // << ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast(this), te) ? " selected" : " not selected" ) + // << LL_ENDL; + // setChanged(ALL_CHANGED); if (!mDrawable.isNull()) { @@ -5469,7 +5470,7 @@ bool can_batch_texture(LLFace* facep) return false; } - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Removed check for turning off animations if (facep->isState(LLFace::TEXTURE_ANIM))//&& facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) // [FIRE-35081] @@ -5619,7 +5620,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } const LLMatrix4* tex_mat = NULL; - // [FIRE-35081] Blurry prims not changing with graphics settings, not happening with SL Viewer + // [FIRE-35081] Blurry prims not changing with graphics settings // Removed check for turning off animations if (facep->isState(LLFace::TEXTURE_ANIM)) //&& facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) // [FIRE-35081] diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index f774f22938..fd18971733 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -111,6 +111,7 @@ #include "llfloatertools.h" #include "llfloatersnapshot.h" // for snapshotFrame #include "llfloaterflickr.h" // for snapshotFrame +#include "fsfloaterprimfeed.h" // for snapshotFrame #include "llsnapshotlivepreview.h" // for snapshotFrame // #include "llpanelface.h" // switchable edit texture/materials panel - include not needed #include "llpathfindingpathtool.h" @@ -788,15 +789,9 @@ void LLPipeline::requestResizeShadowTexture() void LLPipeline::resizeShadowTexture() { - // [FIRE-33200] changing shadowres requires reload - original fix by William Weaver (paperwork) - if(mRT->width == 0 || mRT->height == 0) - { - return; - } - // releaseSunShadowTargets(); releaseSpotShadowTargets(); - allocateShadowBuffer(mRT->width, mRT->height); + allocateShadowBuffer(mRT->screen.getWidth(), mRT->screen.getHeight()); // revert and correct previous shadowres fix that leads to FPS drop (FIRE-3200) gResizeShadowTexture = false; } @@ -8055,12 +8050,12 @@ bool LLPipeline::renderSnapshotFrame(LLRenderTarget* src, LLRenderTarget* dst) } const bool simple_snapshot_visible = LLFloaterReg::instanceVisible("simple_snapshot"); const bool flickr_snapshot_visible = LLFloaterReg::instanceVisible("flickr"); + const bool primfeed_snapshot_visible = LLFloaterReg::instanceVisible("primfeed"); // Primfeed integration const bool snapshot_visible = LLFloaterReg::instanceVisible("snapshot"); - const bool any_snapshot_visible = simple_snapshot_visible || flickr_snapshot_visible || snapshot_visible; + const bool any_snapshot_visible = simple_snapshot_visible || flickr_snapshot_visible || primfeed_snapshot_visible || snapshot_visible; // Primfeed integration if (!show_frame || !any_snapshot_visible || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { return false; - } LLSnapshotLivePreview * previewView = nullptr; if (snapshot_visible) @@ -8074,6 +8069,13 @@ bool LLPipeline::renderSnapshotFrame(LLRenderTarget* src, LLRenderTarget* dst) auto * floater = dynamic_cast(LLFloaterReg::findInstance("flickr")); previewView = floater->getPreviewView(); } + // Primfeed integration + if (primfeed_snapshot_visible && !previewView) + { + auto * floater = dynamic_cast(LLFloaterReg::findInstance("primfeed")); + previewView = floater->getPreviewView(); + } + // if(!previewView) { return false; diff --git a/indra/newview/skins/ansastorm/xui/ja/floater_camera.xml b/indra/newview/skins/ansastorm/xui/ja/floater_camera.xml new file mode 100644 index 0000000000..9f078e0221 --- /dev/null +++ b/indra/newview/skins/ansastorm/xui/ja/floater_camera.xml @@ -0,0 +1,42 @@ + + + + 焦点を中心にカメラを回転します。 + + + 焦点に向けてカメラをズームします。 + + + カメラを上下左右に移動させます。 + + + オブジェクトを見る + + プリセットを使用 + + + + + + + + + + [https://docs.primfeed.com Learn more about Primfeed] + + + diff --git a/indra/newview/skins/default/xui/en/panel_primfeed_photo.xml b/indra/newview/skins/default/xui/en/panel_primfeed_photo.xml new file mode 100644 index 0000000000..061b206e0d --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_primfeed_photo.xml @@ -0,0 +1,352 @@ + + + + + + + + + + + + + + + + + + x + + + + + + + Refreshing... + + + + + + + + Description: + + + + + + + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_snapshot_local.xml b/indra/newview/skins/default/xui/en/panel_snapshot_local.xml index a00a122f0a..022320141d 100644 --- a/indra/newview/skins/default/xui/en/panel_snapshot_local.xml +++ b/indra/newview/skins/default/xui/en/panel_snapshot_local.xml @@ -169,22 +169,22 @@ top_pad="8" follows="left|top" layout="topleft" + label_width="200" + label="Persist location and filename" left="10" - width="20" + width="220" name="local_remember_location_sessions" control_name="FSRememberSnapshotPathSessions"/> - - Save location and filename between sessions - + label_width="200" + label="Include date/time in filename" + left="10" + width="220" + name="local_use_timestamp" + control_name="FSSnapshotLocalNamesWithTimestamps"/> + + + diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index 48235e50ee..a4c5578776 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -110,12 +110,12 @@ top_pad="4" width="81" /> + Problem connecting to Flickr Problem posting to Flickr Problem disconnecting from Flickr + Connecting to Primfeed... + Not Authorized... + Posting... + Problem posting to Primfeed Black & White @@ -2773,6 +2777,8 @@ name="Command_360_Capture_Label">360° Snapshot Beacons Poser Pose your avatar and animated objects + Primfeed + Post directly to your Primfeed account. Capture a 360° equirectangular image diff --git a/indra/newview/skins/default/xui/es/floater_about.xml b/indra/newview/skins/default/xui/es/floater_about.xml index 15cf48db0e..03b6daec06 100644 --- a/indra/newview/skins/default/xui/es/floater_about.xml +++ b/indra/newview/skins/default/xui/es/floater_about.xml @@ -1,5 +1,5 @@ - + [APP_NAME] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2] ([VIEWER_VERSION_3]) [BUILD_DATE] [BUILD_TIME] ([CHANNEL]) [BUILD_TYPE] [[VIEWER_RELEASE_NOTES_URL] Notas de la versión] @@ -42,7 +42,7 @@ Calidad de dibujo (Render quality): [RENDERQUALITY] Error obteniendo las notas de la versión de servidor. - + Para obtener la información más reciente acerca de Firestorm, visita @@ -58,10 +58,10 @@ Los Linden son, con contribuciones de código de: - + - + Firestorm es un proyecto de desarrollo de la comunidad para mejorar la experiencia de uso del Visor de SecondLife(tm). Compilamos contribuciones de varios desarrolladores de la comunidad junto con el código de Linden lab y el nuestro propio para brindarte un visor de calidad, enriquecido con nuevas características y respaldado por un amplio equipo de voluntarios para darte soporte. Firestorm llega a ti a través de The Phoenix Firestorm Project, Inc., una organización sin ánimo de lucro. Forman el Equipo de Desarrollo de Firestorm: diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml index cbfb9a85a0..a85991d175 100644 --- a/indra/newview/skins/default/xui/es/notifications.xml +++ b/indra/newview/skins/default/xui/es/notifications.xml @@ -5001,6 +5001,6 @@ No se podrá deshacer. - Tu instantánea puede ser vista ahora [http://www.flickr.com/photos/upload/edit/?ids=[ID] aquí]. + Tu instantánea puede ser vista ahora [https://www.flickr.com/photos/me/[ID] aquí]. diff --git a/indra/newview/skins/default/xui/es/panel_preferences_colors.xml b/indra/newview/skins/default/xui/es/panel_preferences_colors.xml index e788ad8f03..5e82574653 100644 --- a/indra/newview/skins/default/xui/es/panel_preferences_colors.xml +++ b/indra/newview/skins/default/xui/es/panel_preferences_colors.xml @@ -181,6 +181,17 @@ + + Colores de resaltado de búsqueda de preferencias: + + + Fondo: + + + + Fuente: + + diff --git a/indra/newview/skins/default/xui/fr/floater_fs_poser.xml b/indra/newview/skins/default/xui/fr/floater_fs_poser.xml index 86996e6a3f..2715702cc7 100644 --- a/indra/newview/skins/default/xui/fr/floater_fs_poser.xml +++ b/indra/newview/skins/default/xui/fr/floater_fs_poser.xml @@ -13,11 +13,20 @@ Membres postérieurs Ailes Oreilles/nez + Corps + Corps + Bras + Jambes Tout l'avatar Torse + Colonne vertébrale 1 + Colonne vertébrale 2 + Colonne vertébrale 3 + Colonne vertébrale 4 Poitrine Cou Tête + Crâne Oeil droit Oeil gauche Front, côté gauche @@ -29,13 +38,17 @@ Sourcil, milieu droit Sourcil, intérieur droit Paupière, en haut à gauche + Coin interne gauche de l'œil Paupière, en bas à gauche Paupière, en haut à droite + Coin interne droit de l'œil Paupière en bas à droite Oreille en haut à gauche Oreille en bas à gauche Oreille en haut à droite Oreille en bas à droite + Base du nez + Arête du nez Nez à gauche Nez au milieu Nez à droite @@ -52,16 +65,12 @@ Extrémité de la langue Forme de la mâchoire Milieu du front - Base du nez Dents du haut Lèvre supérieure à gauche Lèvre supérieure à droite Coin gauche de la bouche Coin droit de la bouche Milieu de la lèvre supérieure - Coin interne gauche de l'œil - Coin interne droit de l'œil - Arête du nez Col Bras entier Avant-bras @@ -137,12 +146,36 @@ Droite 2 Droite 3 Droite 4 + Tête + Nuque + Poitrine Fesses Ventre Sein gauche Sein droit + Clavicule gauche + Clavicule droite + Haut du bras gauche + Haut du bras droit + Bas du bras gauche + Bas du bras droit + Main gauche + Main droite + Haut du dos + Taille à gauche + Taille à droite + Bassin + Haut de la jambe gauche + Haut de la jambe droite + Bas de la jambe gauche + Bas de la jambe droite + Pied gauche + Pied droit Charger pose + Enr. pose Charger diff + Enr. diff + Écraser ? @@ -181,8 +214,8 @@ - - - +