Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
d8db0ff
First commit - bare bones of it working - pointing to test page on S3
callumlinden Jun 4, 2025
8d3d6ee
Remove the old avatar selector (Complete Avatars) - replaced by Avata…
callumlinden Jun 4, 2025
f65bb5e
Miniscule change to make the aspect ratio of the non-resizeable float…
callumlinden Jun 4, 2025
ddbcf74
Open Avatar Welcome Pack floater on first login (or cleared settings)…
callumlinden Jun 6, 2025
a366a49
tweak the size of the AWP floater to take account of new image sizes.…
callumlinden Jun 7, 2025
63ef595
Point the URL for the Avatar Welconme Pack at the production location…
callumlinden Jun 11, 2025
44210c4
Merge pull request #4259 from secondlife/callum/awp
Geenz Jun 11, 2025
6619b03
Update viewer version.
Geenz Jun 11, 2025
aa85192
Merge pull request #4262 from secondlife/geenz/2025.04.1-versionbump
Geenz Jun 11, 2025
a6feb3d
Merge pull request #4245 from secondlife/release/2025.04.1
Geenz Jun 23, 2025
06a9e45
Merge pull request #4308 from secondlife/geenz/develop-to-gltf-mesh
Geenz Jun 28, 2025
75db5e8
Revert "Fix LLCharacter base class constness." and restore improvemen…
Ansariel Jun 28, 2025
bca9ba9
Merge pull request #4310 from Ansariel/gltf-import-revert-getjoint
Geenz Jun 28, 2025
64b56d7
#4190 Provide unsupported extension info in log file
maxim-productengine Jul 1, 2025
fcd9a9e
#4242 Better issue logging
akleshchev Jul 1, 2025
230a8ca
private#435 Update GLTF Mesh Import's version to 7.2
akleshchev Jul 1, 2025
76dd938
#4315 Crash in GLTF uploader
akleshchev Jul 1, 2025
900516a
#4142 Fix missed index
akleshchev Jul 1, 2025
b79feb6
#4242 Clarify some operations
akleshchev Jul 2, 2025
55a79ec
#4313 Improved naming of textures
maxim-productengine Jul 2, 2025
5a0bbdc
#4242 Debug dump improvement
akleshchev Jul 2, 2025
10b787e
#4322 Upload Model button is sometimes disabled
akleshchev Jul 2, 2025
f1701d3
#4242 Make sure group array is initialized
akleshchev Jul 3, 2025
dd41001
#4334 Crash at getIsDynamic
akleshchev Jul 3, 2025
ecf220f
#4242 Debug dump improvement #2
akleshchev Jul 3, 2025
b6343d4
#4323 fix for transparent meshes
maxim-productengine Jul 4, 2025
6e65c38
#4319 Thread crashes not being reported to bugsplat
akleshchev Jul 7, 2025
b7dbe0e
#4290 Unresponsive viewer when uploading models
akleshchev Jul 7, 2025
60425f6
#4314 Fix model suffixes
akleshchev Jul 8, 2025
5a8b94b
#4324 sort indices before splits
maxim-productengine Jul 9, 2025
e77e74f
#4314 Follow-up: duplicate logic for mSubmodelID
marchcat Jul 8, 2025
edaf157
#4314 Fix model suffixes #2
akleshchev Jul 9, 2025
19ffeb6
#4357 Crash in LLMeshRepoThread::lodReceived
akleshchev Jul 9, 2025
3da4932
#4296 Crash at renderMorphMasks
akleshchev Jul 9, 2025
07d0fbe
#4294 Make upload order more deterministic
akleshchev Jul 11, 2025
63134f7
#4204 Cache processed materials
marchcat Jul 14, 2025
d033bba
#4204 Refactor material name and texture handling in GLTF loader
marchcat Jul 14, 2025
5a50be4
#4294 Make upload order more deterministic #2
akleshchev Jul 14, 2025
b046a8b
#4204 Cache material names, centralize texture index validation
marchcat Jul 15, 2025
b849e00
#4349 fix repeats cannot be adjusted for specular when a normal map i…
maxim-productengine Jul 16, 2025
7a33f22
#4353 abbreviate text label for standard deviation
maxim-productengine Jul 16, 2025
6e186be
Reapply "Merge develop into glTF mesh import"
akleshchev Jul 17, 2025
af3ef42
Merge branch 'develop' into gltf_mesh_import
akleshchev Jul 17, 2025
33bc6ed
Merge pull request #4380 from secondlife/andreyk/gltf_mesh_import
akleshchev Jul 17, 2025
3f54312
Add support for frametime events per minute.
Geenz Jul 17, 2025
f5d350f
Merge pull request #4381 from secondlife/geenz/frametime-events-per-m…
Geenz Jul 17, 2025
4b69fe3
#4320 MacOS crash handling
akleshchev Jul 19, 2025
8df303e
#4399 Crash at load_face_from_dom_triangles
akleshchev Jul 21, 2025
d848979
#4318 Warn or log when texture gets scaled down
akleshchev Jul 21, 2025
472ea3b
#4393 Handle unknown exceptions in uploader better
akleshchev Jul 22, 2025
e05b32a
#4400 Model Import "use lod above" was not updating
akleshchev Jul 22, 2025
5c746ae
#4415 fix crash when cancelling large model process on MacOS
maxim-productengine Jul 24, 2025
5d4e2c9
#3969 Log time it takes to create inventory from cache
akleshchev Jul 24, 2025
210f559
Media first click interact self check fix (#4406, #4426)
DarlCat Jul 25, 2025
af507ce
Merge branch 'main' into release/2025.05
Geenz Jul 25, 2025
0c39bdf
Merge pull request #4442 from secondlife/geenz/main-to-2025.05
Geenz Jul 25, 2025
c4204a9
Media first click interact large number value fix
DarlCat Jul 24, 2025
6ed9974
Fix incorrectly calculated number in comment and where it was referenced
DarlCat Jul 24, 2025
31f8ebf
Update test plan to match current functionality per suggested/request…
DarlCat Jul 25, 2025
4799f2e
Media first click interact group check fix
DarlCat Jul 24, 2025
a588add
Media first click interact friend check fix
DarlCat Jul 24, 2025
288bce1
#4455 Division by zero in updateFrameStats
akleshchev Jul 28, 2025
a33fda4
#4339 Remade fix for world map's find button
akleshchev Jul 30, 2025
8240af0
#4465 modify vertex limit threshold for starting splitting
maxim-productengine Jul 31, 2025
7255933
#3785 Set default `MediaFirstClickInteract` value to 31 (Landowner ob…
marchcat Aug 2, 2025
f338b91
#4483 Fix gltf not opening unicode paths
akleshchev Aug 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,10 @@ jobs:
prefix=${ba[0]}
if [ "$prefix" == "project" ]; then
IFS='_' read -ra prj <<< "${ba[1]}"
prj_str="${prj[*]}"
# uppercase first letter of each word
export viewer_channel="Second Life Project ${prj[*]^}"
capitalized=$(echo "$prj_str" | awk '{for (i=1; i<=NF; i++) $i = toupper(substr($i,1,1)) substr($i,2); print}')
export viewer_channel="Second Life Project $capitalized"
elif [[ "$prefix" == "release" || "$prefix" == "main" ]];
then
export viewer_channel="Second Life Release"
Expand Down Expand Up @@ -455,7 +457,6 @@ jobs:
prerelease: true
generate_release_notes: true
target_commitish: ${{ github.sha }}
previous_tag: release
append_body: true
fail_on_unmatched_files: true
files: |
Expand Down
14 changes: 6 additions & 8 deletions doc/testplans/PRIM_MEDIA_FIRST_CLICK_INTERACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,11 @@ Perform the testing procedure on both sets of cubes.

Ensure that debug setting `MediaFirstClickInteract` is set to `4`

This test case requires two pairs of cubes, and the second pair must be deeded or set to a group that your testing account is a member of, but does not have set as active at the beginning of the test. As long as the second set of cubes is set to a group that your primary test account is a member of, the avatar that owns them does not matter.
This test case requires two cubes, and the second cube must be deeded or set to a group that your testing account is a member of. As long as the second set of cubes is set to a group that your test account is a member of, the avatar that owns them does not matter.

1. Perform the testing procedure on both sets of cubes.
2. Activate the group that the second set of cubes is set / deeded to
3. Perform the testing procedure on both sets of cubes once more.
Perform the testing procedure on both sets of cubes.

**Expected observations:** Both cubes owned by your primary testing account will not react to mouse cursor hover events and clicks without needing a focus click. Cube A set to group will react to mouse cursor hover events and clicks without needing a focus click, but Cube B will not.
**Expected observations:** The cube owned by your primary account will not react to mouse cursor hover events and clicks without needing a focus click. The cube set to group will react to mouse cursor hover events and clicks without needing a focus click.

### Case 5 (MEDIA_FIRST_CLICK_FRIEND)

Expand Down Expand Up @@ -144,16 +142,16 @@ Note: This requires the avatar that is performing the tests to physically be in

### Case 7 (MEDIA_FIRST_CLICK_ANY) (optional)

Ensure that debug setting `MediaFirstClickInteract` is set to `31`
Ensure that debug setting `MediaFirstClickInteract` is set to `32767`

Repeat test cases 1-6.

1. Test case 1 should fail
2. Test cases 2-6 should pass

### Case 8 (MEDIA_FIRST_CLICK_ALL) (optional)
### Case 8 (MEDIA_FIRST_CLICK_BYPASS_MOAP_FLAG) (optional)

Ensure that debug setting `MediaFirstClickInteract` is set to `1073741824`
Ensure that debug setting `MediaFirstClickInteract` is set to `65535`

Repeat test cases 1-6, there is no pass/fail for this run.

Expand Down
1 change: 1 addition & 0 deletions indra/llappearance/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ set(llappearance_SOURCE_FILES
llavatarjoint.cpp
llavatarjointmesh.cpp
lldriverparam.cpp
lljointdata.h
lllocaltextureobject.cpp
llpolyskeletaldistortion.cpp
llpolymesh.cpp
Expand Down
66 changes: 64 additions & 2 deletions indra/llappearance/llavatarappearance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@
#include "llavatarappearance.h"
#include "llavatarappearancedefines.h"
#include "llavatarjointmesh.h"
#include "lljointdata.h"
#include "llstl.h"
#include "lldir.h"
#include "llpolymorph.h"
#include "llpolymesh.h"
#include "llpolyskeletaldistortion.h"
#include "llstl.h"
#include "lltexglobalcolor.h"
#include "llwearabledata.h"
#include "boost/bind.hpp"
#include "boost/tokenizer.hpp"
#include "v4math.h"

using namespace LLAvatarAppearanceDefines;

Expand Down Expand Up @@ -71,11 +72,13 @@ class LLAvatarBoneInfo
mChildren.clear();
}
bool parseXml(LLXmlTreeNode* node);
glm::mat4 getJointMatrix();

private:
std::string mName;
std::string mSupport;
std::string mAliases;
std::string mGroup;
bool mIsJoint;
LLVector3 mPos;
LLVector3 mEnd;
Expand Down Expand Up @@ -105,11 +108,17 @@ class LLAvatarSkeletonInfo
S32 getNumBones() const { return mNumBones; }
S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }

private:
typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
static void getJointMatricesAndHierarhy(
LLAvatarBoneInfo* bone_info,
LLJointData& data,
const glm::mat4& parent_mat);

private:
S32 mNumBones;
S32 mNumCollisionVolumes;
LLAvatarAppearance::joint_alias_map_t mJointAliasMap;
typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
bone_info_list_t mBoneInfoList;
};

Expand Down Expand Up @@ -1598,6 +1607,15 @@ bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
mSupport = "base";
}

// Skeleton has 133 bones, but shader only allows 110 (LL_MAX_JOINTS_PER_MESH_OBJECT)
// Groups can be used by importer to cut out unused groups of joints
static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
if (!node->getFastAttributeString(group_string, mGroup))
{
LL_WARNS() << "Bone without group " << mName << LL_ENDL;
mGroup = "global";
}

if (mIsJoint)
{
static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
Expand All @@ -1623,6 +1641,21 @@ bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
return true;
}


glm::mat4 LLAvatarBoneInfo::getJointMatrix()
{
glm::mat4 mat(1.0f);
// 1. Scaling
mat = glm::scale(mat, glm::vec3(mScale[0], mScale[1], mScale[2]));
// 2. Rotation (Euler angles rad)
mat = glm::rotate(mat, mRot[0], glm::vec3(1, 0, 0));
mat = glm::rotate(mat, mRot[1], glm::vec3(0, 1, 0));
mat = glm::rotate(mat, mRot[2], glm::vec3(0, 0, 1));
// 3. Position
mat = glm::translate(mat, glm::vec3(mPos[0], mPos[1], mPos[2]));
return mat;
}

//-----------------------------------------------------------------------------
// LLAvatarSkeletonInfo::parseXml()
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -1653,6 +1686,25 @@ bool LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
return true;
}

void LLAvatarSkeletonInfo::getJointMatricesAndHierarhy(
LLAvatarBoneInfo* bone_info,
LLJointData& data,
const glm::mat4& parent_mat)
{
data.mName = bone_info->mName;
data.mJointMatrix = bone_info->getJointMatrix();
data.mScale = glm::vec3(bone_info->mScale[0], bone_info->mScale[1], bone_info->mScale[2]);
data.mRotation = bone_info->mRot;
data.mRestMatrix = parent_mat * data.mJointMatrix;
data.mIsJoint = bone_info->mIsJoint;
data.mGroup = bone_info->mGroup;
for (LLAvatarBoneInfo* child_info : bone_info->mChildren)
{
LLJointData& child_data = data.mChildren.emplace_back();
getJointMatricesAndHierarhy(child_info, child_data, data.mRestMatrix);
}
}

//Make aliases for joint and push to map.
void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)
{
Expand Down Expand Up @@ -1714,6 +1766,16 @@ const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases
return mJointAliasMap;
}

void LLAvatarAppearance::getJointMatricesAndHierarhy(std::vector<LLJointData> &data) const
{
glm::mat4 identity(1.f);
for (LLAvatarBoneInfo* bone_info : sAvatarSkeletonInfo->mBoneInfoList)
{
LLJointData& child_data = data.emplace_back();
LLAvatarSkeletonInfo::getJointMatricesAndHierarhy(bone_info, child_data, identity);
}
}


//-----------------------------------------------------------------------------
// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
Expand Down
6 changes: 5 additions & 1 deletion indra/llappearance/llavatarappearance.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@
#include "lltexlayer.h"
#include "llviewervisualparam.h"
#include "llxmltree.h"
#include "v4math.h"

class LLTexLayerSet;
class LLTexGlobalColor;
class LLTexGlobalColorInfo;
class LLWearableData;
class LLAvatarBoneInfo;
class LLAvatarSkeletonInfo;
class LLJointData;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// LLAvatarAppearance
Expand Down Expand Up @@ -153,7 +155,9 @@ class LLAvatarAppearance : public LLCharacter
const avatar_joint_list_t& getSkeleton() { return mSkeleton; }
typedef std::map<std::string, std::string, std::less<>> joint_alias_map_t;
const joint_alias_map_t& getJointAliases();

typedef std::map<std::string, std::string> joint_parent_map_t; // matrix plus parent
typedef std::map<std::string, glm::mat4> joint_rest_map_t;
void getJointMatricesAndHierarhy(std::vector<LLJointData> &data) const;

protected:
static bool parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree);
Expand Down
66 changes: 66 additions & 0 deletions indra/llappearance/lljointdata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @file lljointdata.h
* @brief LLJointData class for holding individual joint data and skeleton
*
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2025, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/

#ifndef LL_LLJOINTDATA_H
#define LL_LLJOINTDATA_H

#include "v4math.h"

// may be just move LLAvatarBoneInfo
class LLJointData
{
public:
std::string mName;
std::string mGroup;
glm::mat4 mJointMatrix;
glm::mat4 mRestMatrix;
glm::vec3 mScale;
LLVector3 mRotation;

typedef std::vector<LLJointData> bones_t;
bones_t mChildren;

bool mIsJoint; // if not, collision_volume
enum SupportCategory
{
SUPPORT_BASE,
SUPPORT_EXTENDED
};
SupportCategory mSupport;
void setSupport(const std::string& support)
{
if (support == "extended")
{
mSupport = SUPPORT_EXTENDED;
}
else
{
mSupport = SUPPORT_BASE;
}
}
};

#endif //LL_LLJOINTDATA_H
29 changes: 18 additions & 11 deletions indra/llappearance/lltexlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
{
if (!force_render && !hasMorph())
{
LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL;
LL_DEBUGS("Morph") << "skipping renderMorphMasks for " << getUUID() << LL_ENDL;
return;
}
LL_PROFILE_ZONE_SCOPED;
Expand Down Expand Up @@ -1325,7 +1325,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
success &= param->render( x, y, width, height );
if (!success && !force_render)
{
LL_DEBUGS() << "Failed to render param " << param->getID() << " ; skipping morph mask." << LL_ENDL;
LL_DEBUGS("Morph") << "Failed to render param " << param->getID() << " ; skipping morph mask." << LL_ENDL;
return;
}
}
Expand Down Expand Up @@ -1365,7 +1365,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
}
else
{
LL_WARNS() << "Skipping rendering of " << getInfo()->mStaticImageFileName
LL_WARNS("Morph") << "Skipping rendering of " << getInfo()->mStaticImageFileName
<< "; expected 1 or 4 components." << LL_ENDL;
}
}
Expand Down Expand Up @@ -1404,8 +1404,8 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
// We can get bad morph masks during login, on minimize, and occasional gl errors.
// We should only be doing this when we believe something has changed with respect to the user's appearance.
{
LL_DEBUGS("Avatar") << "gl alpha cache of morph mask not found, doing readback: " << getName() << LL_ENDL;
// clear out a slot if we have filled our cache
LL_DEBUGS("Morph") << "gl alpha cache of morph mask not found, doing readback: " << getName() << LL_ENDL;
// clear out a slot if we have filled our cache
S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1;
while ((S32)mAlphaCache.size() >= max_cache_entries)
{
Expand Down Expand Up @@ -1444,13 +1444,20 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
}

glGetTexImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);

U8* alpha_cursor = alpha_data;
U8* pixel = temp;
for (int i = 0; i < pixels; i++)
GLenum error = glGetError();
if (error != GL_NO_ERROR)
{
LL_INFOS("Morph") << "GL Error while reading back morph texture. Error code: " << error << LL_ENDL;
}
else
{
*alpha_cursor++ = pixel[3];
pixel += 4;
U8* alpha_cursor = alpha_data;
U8* pixel = temp;
for (int i = 0; i < pixels; i++)
{
*alpha_cursor++ = pixel[3];
pixel += 4;
}
}

gGL.getTexUnit(0)->disable();
Expand Down
Loading
Loading