Merge branch 'project/gltf_development' of https://github.com/secondlife/viewer

# Conflicts:
#	indra/newview/gltf/primitive.cpp
#	indra/newview/lldynamictexture.cpp
#	indra/newview/llfloaterregioninfo.h
#	indra/newview/lltexturectrl.cpp
#	indra/newview/lltinygltfhelper.cpp
#	indra/newview/llvlcomposition.cpp
#	indra/newview/llvlcomposition.h
#	indra/newview/llvovolume.cpp
master
Ansariel 2024-06-13 03:21:12 +02:00
commit 050d2fefab
44 changed files with 779 additions and 317 deletions

View File

@ -2,6 +2,7 @@
1b68f71348ecf3983b76b40d7940da8377f049b7
# Trim trailing whitespace
a0b3021bdcf76859054fda8e30abb3ed47749e83
8444cd9562a6a7b755fcb075864e205122354192
# Wrong line endings
1b67dd855c41f5a0cda7ec2a68d98071986ca703
6cc7dd09d5e69cf57e6de7fb568a0ad2693f9c9a

View File

@ -1,13 +1,14 @@
# PBR Terrain Appearance
## Tiling
## Tiling Without Texture Transforms
This section assumes the PBR terrain of the current region and adjacent regions have the default texture transforms.
The southwest corner of a region with PBR materials should exactly match up with the bottom left corner of the material texture(s).
If two adjacent regions have the same PBR terrain settings, then:
If two adjacent regions have the same PBR terrain settings, then there should not be seams between the two regions at their shared border.
- There should not be seams between the two regions at their shared border
- The ground should not suddenly slide beneath the avatar when moving between regions (except due to movement of the avatar, which is not covered by this test plan)
The ground should not suddenly slide beneath the avatar when moving between two PBR terrain regions (except due to movement of the avatar, which is not covered by this test plan)
## Feature Gating
@ -35,3 +36,17 @@ Availability of PBR textures varies by machine and graphics setting:
### PBR Alpha
PBR terrain does not support materials with alpha blend or double-sided. In addition, the viewer does not make any guarantees about what will render behind the terrain if alpha is used.
## PBR Terrain Texture Transforms
Like PBR materials on prims, PBR terrain repeats are based on the [KHR\_texture\_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) spec, and thus should be expected to behave the same way.
The southwest corner of a region, at z=0, is the UV origin for all texture coordinates of the whole region. Unless an offset is also applied, scale and rotation of the terrain texture transforms are relative to that point.
When an avatar faces north and looks down at flat ground, the textures of the materials should appear to face upright, unless a rotation is applied.
If triplanar mapping is enabled, and an avatar faces an axially-aligned wall, the textures of the materials should appear to face upright, unless a rotation is applied.
Textures of materials should not appear mirrored.
When triplanar mapping is enabled, rotations on the axially aligned walls should apply in the same direction as they would on flat ground.

View File

@ -12,6 +12,10 @@ All tests in this section assume the PBR terrain feature flag is enabled, and th
### Feature Availability
These features are related to UI, where the Region/Estate floater is opened to the terrain Tab.
#### Feature: PBR Terrain
On the client, the advanced setting `RenderTerrainPBREnabled` is the PBR terrain feature flag.
The PBR terrain feature flag should be set automatically when logging in/teleporting to a new region.
@ -29,6 +33,24 @@ When the PBR terrain feature flag is enabled:
- The "PBR Metallic Roughness" checkbox should be visible
- The user should be able to apply PBR terrain or textures to the region, depending on if the "PBR Metallic Roughness" checkbox is checked.
#### Feature: PBR Terrain Texture Transforms
On the client, the advanced setting, `RenderTerrainPBRTransformsEnabled` is the PBR terrain texture transform flag. Generally, this feature should not be expected to work correctly unless the PBR terrain feature is also enabled.
The PBR terrain texture transform flag should be set automatically when logging in/teleporting to a new region.
- The flag should be enabled on regions where the PBR terrain texture transform feature is enabled
- Otherwise the flag should be disabled
When the PBR terrain texture transform feature is enabled, the UI of the Terrain tab should be overhauled. Availability of features depends on the type of terrain.
When "PBR Metallic Roughness" is checked:
- There should be a way for the user to change the texture transforms for the terrain in the current region
- For each of the four swatches, the user can change the scale, offset, and rotation of that swatch. Nonuniform scale is allowed
When "PBR Metallic Roughness" is unchecked, the controls for texture transforms should be hidden.
### Current Composition Type
When the Region/Estate floater is opened to the terrain Tab, the current terrain should be shown in the four swatches, and the "PBR Metallic Roughness" checkbox should be checked or unchecked accordingly.

View File

@ -328,14 +328,16 @@ public:
// bit 0 = alpha mode blend (1) or opaque (0)
// bit 1 = rigged (1) or static (0)
// bit 2 = unlit (1) or lit (0)
// bit 3 = single (0) or multi (1) uv coordinates
struct GLTFVariant
{
constexpr static U8 ALPHA_BLEND = 1;
constexpr static U8 RIGGED = 2;
constexpr static U8 UNLIT = 4;
constexpr static U8 MULTI_UV = 8;
};
constexpr static U8 NUM_GLTF_VARIANTS = 8;
constexpr static U8 NUM_GLTF_VARIANTS = 16;
std::vector<LLGLSLShader> mGLTFVariants;

View File

@ -1731,7 +1731,7 @@ void LLRender::flush()
if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
{
vb->setTexCoordData(mTexcoordsp.get());
vb->setTexCoord0Data(mTexcoordsp.get());
}
if (attribute_mask & LLVertexBuffer::MAP_COLOR)

View File

@ -1184,7 +1184,13 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("texture_base_color_transform"); // (GLTF)
mReservedUniforms.push_back("texture_normal_transform"); // (GLTF)
mReservedUniforms.push_back("texture_metallic_roughness_transform"); // (GLTF)
mReservedUniforms.push_back("texture_occlusion_transform"); // (GLTF)
mReservedUniforms.push_back("texture_emissive_transform"); // (GLTF)
mReservedUniforms.push_back("base_color_texcoord"); // (GLTF)
mReservedUniforms.push_back("emissive_texcoord"); // (GLTF)
mReservedUniforms.push_back("normal_texcoord"); // (GLTF)
mReservedUniforms.push_back("metallic_roughness_texcoord"); // (GLTF)
mReservedUniforms.push_back("occlusion_texcoord"); // (GLTF)
mReservedUniforms.push_back("terrain_texture_transforms"); // (GLTF)

View File

@ -56,7 +56,13 @@ public:
TEXTURE_BASE_COLOR_TRANSFORM, // "texture_base_color_transform" (GLTF)
TEXTURE_NORMAL_TRANSFORM, // "texture_normal_transform" (GLTF)
TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, // "texture_metallic_roughness_transform" (GLTF)
TEXTURE_OCCLUSION_TRANSFORM, // "texture_occlusion_transform" (GLTF)
TEXTURE_EMISSIVE_TRANSFORM, // "texture_emissive_transform" (GLTF)
BASE_COLOR_TEXCOORD, // "base_color_texcoord" (GLTF)
EMISSIVE_TEXCOORD, // "emissive_texcoord" (GLTF)
NORMAL_TEXCOORD, // "normal_texcoord" (GLTF)
METALLIC_ROUGHNESS_TEXCOORD, // "metallic_roughness_texcoord" (GLTF)
OCCLUSION_TEXCOORD, // "occlusion_texcoord" (GLTF)
TERRAIN_TEXTURE_TRANSFORMS, // "terrain_texture_transforms" (GLTF)

View File

@ -1661,7 +1661,7 @@ void LLVertexBuffer::setPositionData(const LLVector4a* data)
flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data, mMappedData);
}
void LLVertexBuffer::setTexCoordData(const LLVector2* data)
void LLVertexBuffer::setTexCoord0Data(const LLVector2* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
@ -1669,6 +1669,14 @@ void LLVertexBuffer::setTexCoordData(const LLVector2* data)
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setTexCoord1Data(const LLVector2* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD1], mOffsets[TYPE_TEXCOORD1] + sTypeSize[TYPE_TEXCOORD1] * getNumVerts() - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setColorData(const LLColor4U* data)
{
#if !LL_DARWIN

View File

@ -200,7 +200,8 @@ public:
void setTangentData(const LLVector4a* data);
void setWeight4Data(const LLVector4a* data);
void setJointData(const U64* data);
void setTexCoordData(const LLVector2* data);
void setTexCoord0Data(const LLVector2* data);
void setTexCoord1Data(const LLVector2* data);
void setColorData(const LLColor4U* data);
void setIndexData(const U16* data);
void setIndexData(const U32* data);

View File

@ -37,8 +37,8 @@ uniform sampler2D emissiveMap;
uniform vec3 emissiveColor;
in vec3 vary_position;
in vec4 vertex_color;
in vec2 base_color_texcoord;
in vec2 emissive_texcoord;
in vec2 base_color_uv;
in vec2 emissive_uv;
uniform float minimum_alpha;
void mirrorClip(vec3 pos);
@ -59,8 +59,9 @@ uniform float roughnessFactor;
in vec3 vary_normal;
in vec3 vary_tangent;
flat in float vary_sign;
in vec2 normal_texcoord;
in vec2 metallic_roughness_texcoord;
in vec2 normal_uv;
in vec2 metallic_roughness_uv;
in vec2 occlusion_uv;
#endif
// ==================================
@ -164,7 +165,7 @@ void main()
vec3 pos = vary_position;
mirrorClip(pos);
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
vec4 basecolor = texture(diffuseMap, base_color_uv.xy).rgba;
basecolor.rgb = srgb_to_linear(basecolor.rgb);
basecolor *= vertex_color;
@ -174,7 +175,7 @@ void main()
}
vec3 emissive = emissiveColor;
emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb);
emissive *= srgb_to_linear(texture(emissiveMap, emissive_uv.xy).rgb);
// ==================================
// ==================================
@ -184,7 +185,7 @@ void main()
// ==================================
#ifndef UNLIT
// from mikktspace.com
vec3 vNt = texture(normalMap, normal_texcoord.xy).xyz*2.0-1.0;
vec3 vNt = texture(normalMap, normal_uv.xy).xyz*2.0-1.0;
float sign = vary_sign;
vec3 vN = vary_normal;
vec3 vT = vary_tangent.xyz;
@ -198,8 +199,8 @@ void main()
// occlusion 1.0
// roughness 0.0
// metal 0.0
vec3 orm = texture(metallicRoughnessMap, metallic_roughness_texcoord.xy).rgb;
orm.r = texture(occlusionMap, metallic_roughness_texcoord.xy).r;
vec3 orm = texture(metallicRoughnessMap, metallic_roughness_uv.xy).rgb;
orm.r = texture(occlusionMap, occlusion_uv.xy).r;
orm.g *= roughnessFactor;
orm.b *= metallicFactor;
#endif

View File

@ -33,33 +33,97 @@ uniform mat4 projection_matrix;
uniform mat3 normal_matrix;
uniform mat4 modelview_projection_matrix;
#endif
uniform mat4 texture_matrix0;
uniform vec4[2] texture_base_color_transform;
uniform vec4[2] texture_normal_transform;
uniform vec4[2] texture_metallic_roughness_transform;
uniform vec4[2] texture_emissive_transform;
uniform vec4[2] texture_occlusion_transform;
in vec3 position;
in vec4 diffuse_color;
in vec2 texcoord0;
out vec2 base_color_texcoord;
out vec2 emissive_texcoord;
out vec2 base_color_uv;
out vec2 emissive_uv;
out vec4 vertex_color;
out vec3 vary_position;
#ifndef UNLIT
in vec3 normal;
in vec4 tangent;
out vec2 normal_texcoord;
out vec2 metallic_roughness_texcoord;
out vec2 normal_uv;
out vec2 metallic_roughness_uv;
out vec2 occlusion_uv;
out vec3 vary_tangent;
flat out float vary_sign;
out vec3 vary_normal;
vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
#endif
vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
#ifdef MULTI_UV
in vec2 texcoord1;
uniform int base_color_texcoord;
uniform int emissive_texcoord;
#ifndef UNLIT
uniform int normal_texcoord;
uniform int metallic_roughness_texcoord;
uniform int occlusion_texcoord;
#endif
#endif
vec2 gltf_texture_transform(vec2 texcoord, vec4[2] p)
{
texcoord.y = 1.0 - texcoord.y;
vec2 Scale = p[0].xy;
float Rotation = -p[0].z;
vec2 Offset = vec2(p[0].w, p[1].x);
mat3 translation = mat3(1,0,0, 0,1,0, Offset.x, Offset.y, 1);
mat3 rotation = mat3(
cos(Rotation), sin(Rotation), 0,
-sin(Rotation), cos(Rotation), 0,
0, 0, 1);
mat3 scale = mat3(Scale.x,0,0, 0,Scale.y,0, 0,0,1);
mat3 matrix = translation * rotation * scale;
vec2 uvTransformed = ( matrix * vec3(texcoord.xy, 1) ).xy;
uvTransformed.y = 1.0 - uvTransformed.y;
return uvTransformed;
}
#ifndef UNLIT
vec3 gltf_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform)
{ //derived from tangent_space_transform in textureUtilV.glsl
vec2 weights = vec2(0, 1);
// Convert to left-handed coordinate system
weights.y = -weights.y;
// Apply KHR_texture_transform (rotation only)
float khr_rotation = khr_gltf_transform[0].z;
mat2 khr_rotation_mat = mat2(
cos(khr_rotation),-sin(khr_rotation),
sin(khr_rotation), cos(khr_rotation)
);
weights = khr_rotation_mat * weights;
// Convert back to right-handed coordinate system
weights.y = -weights.y;
// Similar to the MikkTSpace-compatible method of extracting the binormal
// from the normal and tangent, as seen in the fragment shader
vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz);
return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz);
return vertex_tangent.xyz;
}
#endif
#ifdef ALPHA_BLEND
@ -136,14 +200,41 @@ void main()
gl_Position = vert;
#endif
base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0);
emissive_texcoord = texture_transform(texcoord0, texture_emissive_transform, texture_matrix0);
vec2 bcuv;
vec2 emuv;
#ifndef UNLIT
normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0);
metallic_roughness_texcoord = texture_transform(texcoord0, texture_metallic_roughness_transform, texture_matrix0);
#ifdef MULTI_UV
vec2 uv[2];
uv[0] = texcoord0;
uv[1] = texcoord1;
bcuv = uv[base_color_texcoord];
emuv = uv[emissive_texcoord];
#else
bcuv = texcoord0;
emuv = texcoord0;
#endif
base_color_uv = gltf_texture_transform(bcuv, texture_base_color_transform);
emissive_uv = gltf_texture_transform(emuv, texture_emissive_transform);
#ifndef UNLIT
vec2 normuv;
vec2 rmuv;
vec2 ouv;
#ifdef MULTI_UV
normuv = uv[normal_texcoord];
rmuv = uv[metallic_roughness_texcoord];
ouv = uv[occlusion_texcoord];
#else
normuv = texcoord0;
rmuv = texcoord0;
ouv = texcoord0;
#endif
normal_uv = gltf_texture_transform(normuv, texture_normal_transform);
metallic_roughness_uv = gltf_texture_transform(rmuv, texture_metallic_roughness_transform);
occlusion_uv = gltf_texture_transform(ouv, texture_occlusion_transform);
#endif
#ifndef UNLIT
#ifdef HAS_SKIN
@ -155,7 +246,7 @@ void main()
#endif
n = normalize(n);
vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0));
vary_tangent = normalize(gltf_tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform));
vary_sign = tangent.w;
vary_normal = n;
#endif

View File

@ -108,7 +108,8 @@ void Buffer::erase(Asset& asset, S32 offset, S32 length)
mData.erase(mData.begin() + offset, mData.begin() + offset + length);
mByteLength = mData.size();
llassert(mData.size() <= size_t(INT_MAX));
mByteLength = S32(mData.size());
for (BufferView& view : asset.mBufferViews)
{
@ -141,7 +142,7 @@ bool Buffer::prep(Asset& asset)
}
mData.resize(mByteLength);
if (!file.read((U8*)mData.data(), mData.size()))
if (!file.read((U8*)mData.data(), mByteLength))
{
LL_WARNS("GLTF") << "Failed to load buffer data from asset: " << id << LL_ENDL;
return false;

View File

@ -189,16 +189,15 @@ void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F
if (mFrameTimes.size() > 1)
{
llassert(mFrameTimes.size() <= size_t(U32_MAX));
frameIndex = U32(mFrameTimes.size()) - 2;
t = 1.f;
if (time > mMaxTime)
{
frameIndex = (U32)mFrameTimes.size() - 2;
t = 1.0f;
return;
}
frameIndex = (U32)mFrameTimes.size() - 2;
t = 1.f;
for (U32 i = 0; i < (U32)mFrameTimes.size() - 1; i++)
{
if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1])
@ -382,7 +381,7 @@ void Skin::uploadMatrixPalette(Asset& asset)
glGenBuffers(1, &mUBO);
}
U32 joint_count = llmin(max_joints, mJoints.size());
size_t joint_count = llmin<size_t>(max_joints, mJoints.size());
std::vector<mat4> t_mp;

View File

@ -45,7 +45,8 @@ namespace LL
namespace GLTF
{
static std::unordered_set<std::string> ExtensionsSupported = {
"KHR_materials_unlit"
"KHR_materials_unlit",
"KHR_texture_transform"
};
Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode)
@ -906,6 +907,25 @@ void Material::TextureInfo::serialize(object& dst) const
{
write(mIndex, "index", dst, INVALID_INDEX);
write(mTexCoord, "texCoord", dst, 0);
write_extensions(dst, &mTextureTransform, "KHR_texture_transform");
}
S32 Material::TextureInfo::getTexCoord() const
{
if (mTextureTransform.mPresent && mTextureTransform.mTexCoord != INVALID_INDEX)
{
return mTextureTransform.mTexCoord;
}
return mTexCoord;
}
bool Material::isMultiUV() const
{
return mPbrMetallicRoughness.mBaseColorTexture.getTexCoord() != 0 ||
mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord() != 0 ||
mNormalTexture.getTexCoord() != 0 ||
mOcclusionTexture.getTexCoord() != 0 ||
mEmissiveTexture.getTexCoord() != 0;
}
const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src)
@ -914,6 +934,7 @@ const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src)
{
copy(src, "index", mIndex);
copy(src, "texCoord", mTexCoord);
copy_extensions(src, "KHR_texture_transform", &mTextureTransform);
}
return *this;
@ -931,17 +952,16 @@ bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const
void Material::OcclusionTextureInfo::serialize(object& dst) const
{
write(mIndex, "index", dst, INVALID_INDEX);
write(mTexCoord, "texCoord", dst, 0);
TextureInfo::serialize(dst);
write(mStrength, "strength", dst, 1.f);
}
const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const Value& src)
{
TextureInfo::operator=(src);
if (src.is_object())
{
copy(src, "index", mIndex);
copy(src, "texCoord", mTexCoord);
copy(src, "strength", mStrength);
}
@ -950,13 +970,13 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(
void Material::NormalTextureInfo::serialize(object& dst) const
{
write(mIndex, "index", dst, INVALID_INDEX);
write(mTexCoord, "texCoord", dst, 0);
TextureInfo::serialize(dst);
write(mScale, "scale", dst, 1.f);
}
const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const Value& src)
{
TextureInfo::operator=(src);
if (src.is_object())
{
copy(src, "index", mIndex);
@ -1015,6 +1035,41 @@ void Material::Unlit::serialize(object& dst) const
// no members and object has already been created, nothing to do
}
void TextureTransform::getPacked(F32* packed) const
{
packed[0] = mScale.x;
packed[1] = mScale.y;
packed[2] = mRotation;
packed[3] = mOffset.x;
packed[4] = mOffset.y;
packed[5] = packed[6] = packed[7] = 0.f;
}
const TextureTransform& TextureTransform::operator=(const Value& src)
{
mPresent = true;
if (src.is_object())
{
copy(src, "offset", mOffset);
copy(src, "rotation", mRotation);
copy(src, "scale", mScale);
copy(src, "texCoord", mTexCoord);
}
return *this;
}
void TextureTransform::serialize(object& dst) const
{
write(mOffset, "offset", dst, vec2(0.f, 0.f));
write(mRotation, "rotation", dst, 0.f);
write(mScale, "scale", dst, vec2(1.f, 1.f));
write(mTexCoord, "texCoord", dst, -1);
}
void Material::serialize(object& dst) const
{
write(mName, "name", dst);

View File

@ -57,6 +57,21 @@ namespace LL
bool mPresent = false;
};
class TextureTransform : public Extension // KHR_texture_transform implementation
{
public:
vec2 mOffset = vec2(0.f, 0.f);
F32 mRotation = 0.f;
vec2 mScale = vec2(1.f, 1.f);
S32 mTexCoord = INVALID_INDEX;
// get the texture transform as a packed array of floats
// dst MUST point to at least 8 floats
void getPacked(F32* dst) const;
const TextureTransform& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class Material
{
@ -82,9 +97,15 @@ namespace LL
S32 mIndex = INVALID_INDEX;
S32 mTexCoord = 0;
TextureTransform mTextureTransform;
bool operator==(const TextureInfo& rhs) const;
bool operator!=(const TextureInfo& rhs) const;
// get the UV channel that should be used for sampling this texture
// returns mTextureTransform.mTexCoord if present and valid, otherwise mTexCoord
S32 getTexCoord() const;
const TextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
@ -135,6 +156,8 @@ namespace LL
bool mDoubleSided = false;
Unlit mUnlit;
bool isMultiUV() const;
const Material& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};

View File

@ -590,8 +590,8 @@ namespace LL
// Write all extensions to dst.extensions
// Usage:
// write_extensions(dst,
// "KHR_materials_unlit", mUnlit,
// "KHR_materials_pbrSpecularGlossiness", mPbrSpecularGlossiness);
// mUnlit, "KHR_materials_unlit",
// mPbrSpecularGlossiness, "KHR_materials_pbrSpecularGlossiness");
// returns true if any of the extensions are written
template<class... Types>
inline bool write_extensions(boost::json::object& dst, Types... args)
@ -816,6 +816,39 @@ namespace LL
return true;
}
// vec2
template<>
inline bool copy(const Value& src, vec2& dst)
{
if (src.is_array())
{
const boost::json::array& arr = src.as_array();
if (arr.size() == 2)
{
std::error_code ec;
vec2 t;
t.x = arr[0].to_number<F32>(ec); if (ec) return false;
t.y = arr[1].to_number<F32>(ec); if (ec) return false;
dst = t;
return true;
}
}
return false;
}
template<>
inline bool write(const vec2& src, Value& dst)
{
dst = boost::json::array();
boost::json::array& arr = dst.as_array();
arr.resize(2);
arr[0] = src.x;
arr[1] = src.y;
return true;
}
// bool
template<>
inline bool copy(const Value& src, bool& dst)

View File

@ -42,30 +42,45 @@ using namespace boost::json;
// Mesh data useful for Mikktspace tangent generation (and flat normal generation)
struct MikktMesh
{
std::vector<LLVector3> p;
std::vector<LLVector3> n;
std::vector<LLVector2> tc;
std::vector<LLVector4> w;
std::vector<LLVector4> t;
std::vector<LLColor4U> c;
std::vector<U64> j;
std::vector<LLVector3> p; //positions
std::vector<LLVector3> n; //normals
std::vector<LLVector4> t; //tangents
std::vector<LLVector2> tc0; //texcoords 0
std::vector<LLVector2> tc1; //texcoords 1
std::vector<LLColor4U> c; //colors
std::vector<LLVector4> w; //weights
std::vector<U64> j; //joints
// initialize from src primitive and make an unrolled triangle list
// returns false if the Primitive cannot be converted to a triangle list
bool copy(const Primitive* prim)
{
bool indexed = !prim->mIndexArray.empty();
U32 vert_count = indexed ? prim->mIndexArray.size() : prim->mPositions.size();
size_t vert_count = indexed ? prim->mIndexArray.size() : prim->mPositions.size();
if (prim->mMode != Primitive::Mode::TRIANGLES)
size_t triangle_count = 0;
if (prim->mMode == Primitive::Mode::TRIANGLE_STRIP ||
prim->mMode == Primitive::Mode::TRIANGLE_FAN)
{
LL_WARNS("GLTF") << "Unsupported primitive mode for conversion to triangles: " << (S32) prim->mMode << LL_ENDL;
triangle_count = vert_count - 2;
}
else if (prim->mMode == Primitive::Mode::TRIANGLES)
{
triangle_count = vert_count / 3;
}
else
{
LL_WARNS("GLTF") << "Unsupported primitive mode for conversion to triangles: " << (S32)prim->mMode << LL_ENDL;
return false;
}
vert_count = triangle_count * 3;
llassert(vert_count <= size_t(U32_MAX)); // triangle_count will also naturally be under the limit
p.resize(vert_count);
n.resize(vert_count);
tc.resize(vert_count);
tc0.resize(vert_count);
c.resize(vert_count);
bool has_normals = !prim->mNormals.empty();
@ -78,6 +93,7 @@ struct MikktMesh
{
t.resize(vert_count);
}
bool rigged = !prim->mWeights.empty();
if (rigged)
{
@ -85,23 +101,69 @@ struct MikktMesh
j.resize(vert_count);
}
for (int i = 0; i < vert_count; ++i)
bool multi_uv = !prim->mTexCoords1.empty();
if (multi_uv)
{
U32 idx = indexed ? prim->mIndexArray[i] : i;
tc1.resize(vert_count);
}
p[i].set(prim->mPositions[idx].getF32ptr());
tc[i].set(prim->mTexCoords[idx]);
c[i] = prim->mColors[idx];
for (U32 tri_idx = 0; tri_idx < U32(triangle_count); ++tri_idx)
{
U32 idx[3];
if (prim->mMode == Primitive::Mode::TRIANGLES)
{
idx[0] = tri_idx * 3;
idx[1] = tri_idx * 3 + 1;
idx[2] = tri_idx * 3 + 2;
}
else if (prim->mMode == Primitive::Mode::TRIANGLE_STRIP)
{
idx[0] = tri_idx;
idx[1] = tri_idx + 1;
idx[2] = tri_idx + 2;
if (tri_idx % 2 != 0)
{
std::swap(idx[1], idx[2]);
}
}
else if (prim->mMode == Primitive::Mode::TRIANGLE_FAN)
{
idx[0] = 0;
idx[1] = tri_idx + 1;
idx[2] = tri_idx + 2;
}
if (indexed)
{
idx[0] = prim->mIndexArray[idx[0]];
idx[1] = prim->mIndexArray[idx[1]];
idx[2] = prim->mIndexArray[idx[2]];
}
for (U32 v = 0; v < 3; ++v)
{
U32 i = tri_idx * 3 + v;
p[i].set(prim->mPositions[idx[v]].getF32ptr());
tc0[i].set(prim->mTexCoords0[idx[v]]);
c[i] = prim->mColors[idx[v]];
if (multi_uv)
{
tc1[i].set(prim->mTexCoords1[idx[v]]);
}
if (has_normals)
{
n[i].set(prim->mNormals[idx].getF32ptr());
n[i].set(prim->mNormals[idx[v]].getF32ptr());
}
if (rigged)
{
w[i].set(prim->mWeights[idx].getF32ptr());
j[i] = prim->mJoints[idx];
w[i].set(prim->mWeights[idx[v]].getF32ptr());
j[i] = prim->mJoints[idx[v]];
}
}
}
@ -110,8 +172,8 @@ struct MikktMesh
void genNormals()
{
U32 tri_count = p.size() / 3;
for (U32 i = 0; i < tri_count; ++i)
size_t tri_count = p.size() / 3;
for (size_t i = 0; i < tri_count; ++i)
{
LLVector3 v0 = p[i * 3];
LLVector3 v1 = p[i * 3 + 1];
@ -138,25 +200,34 @@ struct MikktMesh
void write(Primitive* prim) const
{
//re-weld
meshopt_Stream mos[] =
std::vector<meshopt_Stream> mos =
{
{ &p[0], sizeof(LLVector3), sizeof(LLVector3) },
{ &n[0], sizeof(LLVector3), sizeof(LLVector3) },
{ &t[0], sizeof(LLVector4), sizeof(LLVector4) },
{ &tc[0], sizeof(LLVector2), sizeof(LLVector2) },
{ &c[0], sizeof(LLColor4U), sizeof(LLColor4U) },
{ w.empty() ? nullptr : &w[0], sizeof(LLVector4), sizeof(LLVector4) },
{ j.empty() ? nullptr : &j[0], sizeof(U64), sizeof(U64) }
{ &tc0[0], sizeof(LLVector2), sizeof(LLVector2) },
{ &c[0], sizeof(LLColor4U), sizeof(LLColor4U) }
};
if (!w.empty())
{
mos.push_back({ &w[0], sizeof(LLVector4), sizeof(LLVector4) });
mos.push_back({ &j[0], sizeof(U64), sizeof(U64) });
}
if (!tc1.empty())
{
mos.push_back({ &tc1[0], sizeof(LLVector2), sizeof(LLVector2) });
}
std::vector<U32> remap;
remap.resize(p.size());
U32 stream_count = w.empty() ? 5 : 7;
size_t stream_count = mos.size();
size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, p.size(), p.size(), mos, stream_count);
size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, p.size(), p.size(), mos.data(), stream_count);
prim->mTexCoords.resize(vert_count);
prim->mTexCoords0.resize(vert_count);
prim->mNormals.resize(vert_count);
prim->mTangents.resize(vert_count);
prim->mPositions.resize(vert_count);
@ -166,6 +237,10 @@ struct MikktMesh
prim->mWeights.resize(vert_count);
prim->mJoints.resize(vert_count);
}
if (!tc1.empty())
{
prim->mTexCoords1.resize(vert_count);
}
prim->mIndexArray.resize(remap.size());
@ -178,7 +253,7 @@ struct MikktMesh
prim->mPositions[dst_idx].load3(p[src_idx].mV);
prim->mNormals[dst_idx].load3(n[src_idx].mV);
prim->mTexCoords[dst_idx] = tc[src_idx];
prim->mTexCoords0[dst_idx] = tc0[src_idx];
prim->mTangents[dst_idx].loadua(t[src_idx].mV);
prim->mColors[dst_idx] = c[src_idx];
@ -187,6 +262,11 @@ struct MikktMesh
prim->mWeights[dst_idx].loadua(w[src_idx].mV);
prim->mJoints[dst_idx] = j[src_idx];
}
if (!tc1.empty())
{
prim->mTexCoords1[dst_idx] = tc1[src_idx];
}
}
prim->mGLMode = LLRender::TRIANGLES;
@ -210,8 +290,8 @@ struct MikktMesh
mikk::float3 GetTexCoord(const uint32_t face_num, const uint32_t vert_num)
{
F32* uv = tc[face_num * 3 + vert_num].mV;
return mikk::float3(uv[0], uv[1], 1.0f);
F32* uv = tc0[face_num * 3 + vert_num].mV;
return mikk::float3(uv[0], 1.f-uv[1], 1.0f);
}
mikk::float3 GetNormal(const uint32_t face_num, const uint32_t vert_num)
@ -228,6 +308,14 @@ struct MikktMesh
};
static void vertical_flip(std::vector<LLVector2>& texcoords)
{
for (auto& tc : texcoords)
{
tc[1] = 1.f - tc[1];
}
}
bool Primitive::prep(Asset& asset)
{
// allocate vertex buffer
@ -261,7 +349,11 @@ bool Primitive::prep(Asset& asset)
}
else if (attribName == "TEXCOORD_0")
{
copy(asset, accessor, mTexCoords);
copy(asset, accessor, mTexCoords0);
}
else if (attribName == "TEXCOORD_1")
{
copy(asset, accessor, mTexCoords1);
}
else if (attribName == "JOINTS_0")
{
@ -297,24 +389,28 @@ bool Primitive::prep(Asset& asset)
mask |= LLVertexBuffer::MAP_JOINT;
}
if (mTexCoords.empty())
if (mTexCoords0.empty())
{
mTexCoords.resize(mPositions.size());
mTexCoords0.resize(mPositions.size());
}
// TODO: support more than one texcoord set (or no texcoords)
mask |= LLVertexBuffer::MAP_TEXCOORD0;
if (!mTexCoords1.empty())
{
mask |= LLVertexBuffer::MAP_TEXCOORD1;
}
if (mColors.empty())
{
mColors.resize(mPositions.size(), LLColor4U::white);
}
mShaderVariant = 0;
// TODO: support colorless vertex buffers
mask |= LLVertexBuffer::MAP_COLOR;
mShaderVariant = 0;
bool unlit = false;
// bake material basecolor into color array
@ -332,6 +428,11 @@ bool Primitive::prep(Asset& asset)
mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT;
unlit = true;
}
if (material.isMultiUV())
{
mShaderVariant |= LLGLSLShader::GLTFVariant::MULTI_UV;
}
}
if (mNormals.empty() && !unlit)
@ -411,7 +512,10 @@ bool Primitive::prep(Asset& asset)
}
mVertexBuffer = new LLVertexBuffer(mask);
mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size() * 2); // double the size of the index buffer for 32-bit indices
// we store these buffer sizes as S32 elsewhere
llassert(mPositions.size() <= size_t(S32_MAX));
llassert(mIndexArray.size() <= size_t(S32_MAX / 2));
mVertexBuffer->allocateBuffer(U32(mPositions.size()), U32(mIndexArray.size() * 2)); // double the size of the index buffer for 32-bit indices
mVertexBuffer->setBuffer();
mVertexBuffer->setPositionData(mPositions.data());
@ -434,16 +538,18 @@ bool Primitive::prep(Asset& asset)
}
// flip texcoord y, upload, then flip back (keep the off-spec data in vram only)
for (auto& tc : mTexCoords)
vertical_flip(mTexCoords0);
mVertexBuffer->setTexCoord0Data(mTexCoords0.data());
vertical_flip(mTexCoords0);
if (!mTexCoords1.empty())
{
tc[1] = 1.f - tc[1];
}
mVertexBuffer->setTexCoordData(mTexCoords.data());
for (auto& tc : mTexCoords)
{
tc[1] = 1.f - tc[1];
vertical_flip(mTexCoords1);
mVertexBuffer->setTexCoord1Data(mTexCoords1.data());
vertical_flip(mTexCoords1);
}
if (!mIndexArray.empty())
{
mVertexBuffer->setIndexData(mIndexArray.data());
@ -453,11 +559,14 @@ bool Primitive::prep(Asset& asset)
mVertexBuffer->unbind();
if (mMaterial != INVALID_INDEX)
{
Material& material = asset.mMaterials[mMaterial];
if (material.mAlphaMode == Material::AlphaMode::BLEND)
{
mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND;
}
}
return true;
}
@ -614,13 +723,13 @@ const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start,
//create a proxy LLVolumeFace for the raycast
LLVolumeFace face;
face.mPositions = mPositions.data();
face.mTexCoords = mTexCoords.data();
face.mTexCoords = mTexCoords0.data();
face.mNormals = mNormals.data();
face.mTangents = mTangents.data();
face.mIndices = nullptr; // unreferenced
face.mNumIndices = (S32)mIndexArray.size();
face.mNumVertices = (S32)mPositions.size();
face.mNumIndices = S32(mIndexArray.size());
face.mNumVertices = S32(mPositions.size());
LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out);
intersect.traverse(mOctree);

View File

@ -58,7 +58,8 @@ namespace LL
LLPointer<LLVertexBuffer> mVertexBuffer;
// CPU copy of mesh data, keep these as LLVector types for compatibility with raycasting code
std::vector<LLVector2> mTexCoords;
std::vector<LLVector2> mTexCoords0;
std::vector<LLVector2> mTexCoords1;
std::vector<LLVector4a> mNormals;
std::vector<LLVector4a> mTangents;
std::vector<LLVector4a> mPositions;

View File

@ -244,7 +244,8 @@ void GLTFSceneManager::uploadSelection()
LLFileSystem cache(assetId, LLAssetType::AT_GLTF_BIN, LLFileSystem::WRITE);
auto& data = mUploadingAsset->mBuffers[idx].mData;
cache.write((const U8*)data.data(), data.size());
llassert(data.size() <= size_t(S32_MAX));
cache.write((const U8 *) data.data(), S32(data.size()));
}
};
#if GLTF_SIM_SUPPORT
@ -399,8 +400,9 @@ void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType a
{
LLFileSystem file(id, asset_type, LLFileSystem::READ);
std::string data;
data.resize(file.getSize());
file.read((U8*)data.data(), data.size());
S32 file_size = file.getSize();
data.resize(file_size);
file.read((U8*)data.data(), file_size);
boost::json::value json = boost::json::parse(data);
@ -479,7 +481,8 @@ void GLTFSceneManager::update()
LLFileSystem cache(assetId, LLAssetType::AT_GLTF, LLFileSystem::WRITE);
LL_INFOS("GLTF") << "Uploaded GLTF json: " << assetId << LL_ENDL;
cache.write((const U8 *) buffer.c_str(), buffer.size());
llassert(buffer.size() <= size_t(S32_MAX));
cache.write((const U8 *) buffer.c_str(), S32(buffer.size()));
mUploadingAsset = nullptr;
}
@ -549,10 +552,16 @@ void GLTFSceneManager::render(bool opaque, bool rigged, bool unlit)
void GLTFSceneManager::render(U8 variant)
{
// for debugging, just render the whole scene as opaque
// by traversing the whole scenegraph
// Assumes camera transform is already set and
// appropriate shader is already boundd
// just render the whole scene by traversing the whole scenegraph
// Assumes camera transform is already set and appropriate shader is already bound.
// Eventually we'll want a smarter render pipe that has pre-sorted the scene graph
// into buckets by material and shader.
// HACK -- implicitly render multi-uv variant
if (!(variant & LLGLSLShader::GLTFVariant::MULTI_UV))
{
render((U8) (variant | LLGLSLShader::GLTFVariant::MULTI_UV));
}
gGL.matrixMode(LLRender::MM_MODELVIEW);
@ -663,11 +672,30 @@ static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info,
{
if (info.mIndex != INVALID_INDEX)
{
LLViewerTexture* tex = asset.mImages[asset.mTextures[info.mIndex].mSource].mTexture;
Texture& texture = asset.mTextures[info.mIndex];
LLViewerTexture* tex = asset.mImages[texture.mSource].mTexture;
if (tex)
{
tex->addTextureStats(2048.f * 2048.f);
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex);
S32 channel = LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex);
if (channel != -1 && texture.mSampler != -1)
{ // set sampler state
Sampler& sampler = asset.mSamplers[texture.mSampler];
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sampler.mWrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, sampler.mWrapT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampler.mMagFilter);
// NOTE: do not set min filter. Always respect client preference for min filter
}
else
{
// set default sampler state
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
}
else
{
@ -710,10 +738,10 @@ void GLTFSceneManager::bind(Asset& asset, Material& material)
bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, material.mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep);
F32 base_color_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed);
F32 tf[8];
material.mPbrMetallicRoughness.mBaseColorTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::BASE_COLOR_TEXCOORD, material.mPbrMetallicRoughness.mBaseColorTexture.getTexCoord());
if (!LLPipeline::sShadowRender)
{
@ -728,20 +756,21 @@ void GLTFSceneManager::bind(Asset& asset, Material& material)
shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, material.mPbrMetallicRoughness.mMetallicFactor);
shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(material.mEmissiveFactor));
F32 normal_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, (F32*)normal_packed);
material.mNormalTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::NORMAL_TEXCOORD, material.mNormalTexture.getTexCoord());
F32 metallic_roughness_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, (F32*)metallic_roughness_packed);
material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::METALLIC_ROUGHNESS_TEXCOORD, material.mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord());
F32 emissive_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed);
material.mOcclusionTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_OCCLUSION_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::OCCLUSION_TEXCOORD, material.mOcclusionTexture.getTexCoord());
material.mEmissiveTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::EMISSIVE_TEXCOORD, material.mEmissiveTexture.getTexCoord());
}
}

View File

@ -220,8 +220,8 @@ bool LLViewerDynamicTexture::updateAllInstances()
if (dynamicTexture->needsRender())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("needsRender");
llassert(dynamicTexture->getFullWidth() <= (S32)LLPipeline::MAX_BAKE_WIDTH);
llassert(dynamicTexture->getFullHeight() <= (S32)LLPipeline::MAX_BAKE_WIDTH);
llassert(dynamicTexture->getFullWidth() <= S32(LLPipeline::MAX_BAKE_WIDTH));
llassert(dynamicTexture->getFullHeight() <= S32(LLPipeline::MAX_BAKE_WIDTH));
glClear(GL_DEPTH_BUFFER_BIT);

View File

@ -359,7 +359,8 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, bool
res /= 2;
S32 mip = i - ((S32)mMipChain.size() - mips);
llassert(mMipChain.size() <= size_t(S32_MAX));
GLint mip = i - (S32(mMipChain.size()) - mips);
if (mip >= 0)
{
@ -487,7 +488,8 @@ void LLHeroProbeManager::updateUniforms()
mHeroData.heroSphere.mV[3] = mProbes[0]->mRadius;
}
mHeroData.heroMipCount = (GLint)mMipChain.size();
llassert(mMipChain.size() <= size_t(S32_MAX));
mHeroData.heroMipCount = S32(mMipChain.size());
}
void LLHeroProbeManager::renderDebug()

View File

@ -2398,7 +2398,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)
message_data["region_id"].asUUID(),
position,
local_bin_bucket.data(),
local_bin_bucket.size(),
S32(local_bin_bucket.size()),
local_sender,
message_data["asset_id"].asUUID());
});

View File

@ -957,11 +957,11 @@ const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot(
else if (root_id.notNull())
{
cat_array_t* cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
if (cats)
if(cats)
{
for (auto& p_cat : *cats)
{
if (p_cat && p_cat->getPreferredType() == preferred_type)
if(p_cat && p_cat->getPreferredType() == preferred_type)
{
const LLUUID& folder_id = p_cat->getUUID();
if (rv.isNull() || folder_id < rv)

View File

@ -2768,7 +2768,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
// *HACK: In order to resolve SL-22177, we need to block drags
// from notecards and objects onto other objects.
if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
{
return ACCEPT_NO;
}

View File

@ -253,7 +253,7 @@ static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader
}
static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool unlit, bool use_sun_shadow)
static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool unlit, bool multi_uv, bool use_sun_shadow)
{
variant.mName = shader.mName.c_str();
variant.mFeatures = shader.mFeatures;
@ -275,6 +275,11 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool
variant.addPermutation("UNLIT", "1");
}
if (multi_uv)
{
variant.addPermutation("MULTI_UV", "1");
}
if (alpha_blend)
{
variant.addPermutation("ALPHA_BLEND", "1");
@ -321,8 +326,9 @@ static bool make_gltf_variants(LLGLSLShader& shader, bool use_sun_shadow)
bool alpha_blend = i & LLGLSLShader::GLTFVariant::ALPHA_BLEND;
bool rigged = i & LLGLSLShader::GLTFVariant::RIGGED;
bool unlit = i & LLGLSLShader::GLTFVariant::UNLIT;
bool multi_uv = i & LLGLSLShader::GLTFVariant::MULTI_UV;
if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, unlit, use_sun_shadow))
if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, unlit, multi_uv, use_sun_shadow))
{
return false;
}

View File

@ -428,8 +428,7 @@ const LLUUID (&LLVLComposition::getDefaultTextures())[ASSET_COUNT]
LLVLComposition::LLVLComposition(LLSurface *surfacep, const U32 width, const F32 scale) :
LLTerrainMaterials(),
LLViewerLayer(width, scale),
mParamsReady(false)
LLViewerLayer(width, scale)
{
// Load Terrain Textures - Original ones
const LLUUID (&default_textures)[LLVLComposition::ASSET_COUNT] = LLVLComposition::getDefaultTextures();

View File

@ -116,7 +116,6 @@ public:
bool generateComposition();
// Generate texture from composition values.
bool generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height);
bool generateTexture(const F32 x, const F32 y, const F32 width, const F32 height);
// Use these as indeces ito the get/setters below that use 'corner'
enum ECorner

View File

@ -1982,9 +1982,8 @@ void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LL
LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromHandle(handle);
U32 num_entries = 0;
U32 inmem_entries = 0;
U32 skipped = 0;
inmem_entries = (U32)cache_extras_entry_map.size();
size_t inmem_entries = cache_extras_entry_map.size();
for (auto [local_id, entry] : cache_extras_entry_map)
{
// Only write out GLTFOverrides that we can actually apply again on import.

View File

@ -4865,6 +4865,7 @@ LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const
bool LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32 *face_hitp,
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
{
if (!mbCanSelect
|| mDrawable->isDead()

View File

@ -3,7 +3,6 @@
border="true"
follows="top|left"
height="460"
help_topic="panel_region_terrain_tab"
label="Terrain"
layout="topleft"
left="0"
@ -225,13 +224,12 @@
left="0"
name="terrain_tabs"
tab_position="top"
tab_width="100"
tab_width="110"
tab_padding_right="3"
top_pad="0"
width="700">
<panel
border="true"
class="panel_settings_terrain_elevation"
filename="panel_settings_terrain_elevation.xml"
label="Elevation"
layout="topleft"
@ -240,7 +238,6 @@
name="terrain_elevation_panel" />
<panel
border="true"
class="panel_settings_terrain_transform"
filename="panel_settings_terrain_transform.xml"
label="Transforms"
layout="topleft"
@ -256,8 +253,8 @@
height="20"
label="Apply"
layout="topleft"
left="353"
left="351"
name="apply_btn"
top_delta="290"
top_delta="310"
width="100" />
</panel>

View File

@ -7,6 +7,62 @@
left="0"
name="panel_settings_terrain_transform"
top="0">
<text
type="string"
length="1"
halign="center"
valign="center"
follows="left|top"
height="20"
layout="topleft"
name="terrain0_label"
left="48"
top_delta="0"
width="62">
1
</text>
<text
type="string"
length="1"
halign="center"
valign="center"
follows="left|top"
height="20"
layout="topleft"
name="terrain1_label"
left_delta="110"
top_delta="0"
width="62">
2
</text>
<text
type="string"
length="1"
halign="center"
valign="center"
follows="left|top"
height="20"
layout="topleft"
name="terrain2_label"
left_delta="110"
top_delta="0"
width="62">
3
</text>
<text
type="string"
length="1"
halign="center"
valign="center"
follows="left|top"
height="20"
layout="topleft"
name="terrain3_label"
left_delta="110"
top_delta="0"
width="62">
4
</text>
<text
type="string"
length="1"
@ -17,19 +73,10 @@
layout="topleft"
name="terrain0ScaleU_label"
left="10"
top_pad="3"
top_pad="0"
width="170">
Scale u
</text>
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="-2"
name="terrain0ScaleU_horizontal"
width="430" />
<spinner
follows="left|top"
height="19"
@ -37,7 +84,7 @@
label="Scale u"
label_width="0"
layout="topleft"
left="10"
left="46"
min_val="-100"
max_val="100"
name="terrain0ScaleU"
@ -78,6 +125,15 @@
max_val="100"
name="terrain3ScaleU"
width="64" />
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="8"
name="terrainScaleU_horizontal"
width="432" />
<text
type="string"
length="1"
@ -88,19 +144,10 @@
layout="topleft"
name="terrain0ScaleV_label"
left="10"
top_pad="3"
top_pad="0"
width="170">
Scale v
</text>
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="-2"
name="terrain0ScaleV_horizontal"
width="430" />
<spinner
follows="left|top"
height="19"
@ -108,7 +155,7 @@
label="Scale v"
label_width="0"
layout="topleft"
left="10"
left="46"
min_val="-100"
max_val="100"
name="terrain0ScaleV"
@ -149,6 +196,15 @@
max_val="100"
name="terrain3ScaleV"
width="64" />
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="8"
name="terrainScaleV_horizontal"
width="432" />
<text
type="string"
length="1"
@ -159,19 +215,10 @@
layout="topleft"
name="terrain0Rotation_label"
left="10"
top_pad="3"
top_pad="0"
width="170">
Rotation
</text>
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="-2"
name="terrain0Rotation_horizontal"
width="430" />
<spinner
follows="left|top"
height="19"
@ -179,7 +226,7 @@
label="Rotation"
label_width="0"
layout="topleft"
left="10"
left="46"
min_val="-360"
max_val="360"
name="terrain0Rotation"
@ -192,8 +239,8 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-360"
max_val="360"
name="terrain1Rotation"
width="64" />
<spinner
@ -204,8 +251,8 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-360"
max_val="360"
name="terrain2Rotation"
width="64" />
<spinner
@ -216,10 +263,19 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-360"
max_val="360"
name="terrain3Rotation"
width="64" />
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="8"
name="terrainRotation_horizontal"
width="432" />
<text
type="string"
length="1"
@ -230,19 +286,10 @@
layout="topleft"
name="terrain0OffsetU_label"
left="10"
top_pad="3"
top_pad="0"
width="170">
Offset y
</text>
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="-2"
name="terrain0OffsetU_horizontal"
width="430" />
<spinner
follows="left|top"
height="19"
@ -250,7 +297,7 @@
label="Offset u"
label_width="0"
layout="topleft"
left="10"
left="46"
min_val="-999"
max_val="999"
name="terrain0OffsetU"
@ -263,8 +310,8 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-999"
max_val="999"
name="terrain1OffsetU"
width="64" />
<spinner
@ -275,8 +322,8 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-999"
max_val="999"
name="terrain2OffsetU"
width="64" />
<spinner
@ -287,10 +334,19 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-999"
max_val="999"
name="terrain3OffsetU"
width="64" />
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="8"
name="terrainOffsetU_horizontal"
width="432" />
<text
type="string"
length="1"
@ -301,19 +357,10 @@
layout="topleft"
name="terrain0OffsetV_label"
left="10"
top_pad="3"
top_pad="0"
width="170">
Offset v
</text>
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="-2"
name="terrain0OffsetV_horizontal"
width="430" />
<spinner
follows="left|top"
height="19"
@ -321,7 +368,7 @@
label="Offset v"
label_width="0"
layout="topleft"
left="10"
left="46"
min_val="-999"
max_val="999"
name="terrain0OffsetV"
@ -334,8 +381,8 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-999"
max_val="999"
name="terrain1OffsetV"
width="64" />
<spinner
@ -346,8 +393,8 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-999"
max_val="999"
name="terrain2OffsetV"
width="64" />
<spinner
@ -358,8 +405,17 @@
label_width="0"
layout="topleft"
left_delta="110"
min_val="-100"
max_val="100"
min_val="-999"
max_val="999"
name="terrain3OffsetV"
width="64" />
<view_border
bevel_style="none"
follows="top|left"
height="0"
layout="topleft"
left="8"
top_pad="8"
name="terrainOffsetV_horizontal"
width="432" />
</panel>