diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index b3d81dab9e..cb7f6988d5 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -2,6 +2,7 @@ 1b68f71348ecf3983b76b40d7940da8377f049b7 # Trim trailing whitespace a0b3021bdcf76859054fda8e30abb3ed47749e83 +8444cd9562a6a7b755fcb075864e205122354192 # Wrong line endings 1b67dd855c41f5a0cda7ec2a68d98071986ca703 6cc7dd09d5e69cf57e6de7fb568a0ad2693f9c9a diff --git a/doc/testplans/pbr_terrain_appearance.md b/doc/testplans/pbr_terrain_appearance.md index f6d54029b5..11b501be3a 100644 --- a/doc/testplans/pbr_terrain_appearance.md +++ b/doc/testplans/pbr_terrain_appearance.md @@ -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. diff --git a/doc/testplans/pbr_terrain_composition.md b/doc/testplans/pbr_terrain_composition.md index aadd97a94b..731da90aba 100644 --- a/doc/testplans/pbr_terrain_composition.md +++ b/doc/testplans/pbr_terrain_composition.md @@ -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. diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index a6a5fae5c4..1539b48bd3 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -61,14 +61,14 @@ #include #endif -// static +// static bool LLCoros::on_main_coro() { if (!LLCoros::instanceExists() || LLCoros::getName().empty()) { return true; } - + return false; } diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 00650a2454..369d65407e 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-02 * @brief Manage running boost::coroutine instances - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -100,7 +100,7 @@ public: static bool on_main_coro(); // For debugging, return true if on the main thread and not in a coroutine - // Non-thread-safe code in the main loop should be protected by + // Non-thread-safe code in the main loop should be protected by // llassert(LLCoros::on_main_thread_main_coro()) static bool on_main_thread_main_coro(); @@ -168,7 +168,7 @@ public: * LLCoros::launch()). */ static std::string getName(); - + /** * rethrow() is called by the thread's main fiber to propagate an * exception from any coroutine into the main fiber, where it can engage diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 8006f9d059..3c6743eac9 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-12 * @brief Implementation for llevents. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -423,8 +423,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL float nodePosition = 1.0; - // if the supplied name is empty we are not interested in the ordering mechanism - // and can bypass attempting to find the optimal location to insert the new + // if the supplied name is empty we are not interested in the ordering mechanism + // and can bypass attempting to find the optimal location to insert the new // listener. We'll just tack it on to the end. if (!name.empty()) // should be the same as testing against ANONYMOUS { @@ -569,12 +569,12 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL // Now that newNode has a value that places it appropriately in mSignal, // connect it. LLBoundListener bound = mSignal->connect(nodePosition, listener); - + if (!name.empty()) { // note that we are not tracking anonymous listeners here either. - // This means that it is the caller's responsibility to either assign - // to a TempBoundListerer (scoped_connection) or manually disconnect - // when done. + // This means that it is the caller's responsibility to either assign + // to a TempBoundListerer (scoped_connection) or manually disconnect + // when done. mConnections[name] = bound; } return bound; @@ -641,9 +641,9 @@ bool LLEventMailDrop::post(const LLSD& event) { // forward the call to our base class bool posted = LLEventStream::post(event); - + if (!posted) - { // if the event was not handled we will save it for later so that it can + { // if the event was not handled we will save it for later so that it can // be posted to any future listeners when they attach. mEventHistory.push_back(event); } diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index febeec350c..10df4c8ee1 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -268,7 +268,7 @@ public: F32 mAlphaCutoff; AlphaMode mAlphaMode; - + bool mDoubleSided = false; // Override specific flags for state that can't use off-by-epsilon or UUID diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index fa669f1ae5..c3420bc8c9 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -1276,7 +1276,7 @@ bool LLGLManager::initGL() glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &mMaxUniformBlockSize); - // sanity clamp max uniform block size to 64k just in case + // sanity clamp max uniform block size to 64k just in case // there's some implementation that reports a crazy value mMaxUniformBlockSize = llmin(mMaxUniformBlockSize, 65536); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 32fa0c3cf7..4ecb1f55d6 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -172,11 +172,11 @@ void clear_glerror(); # define llglassertok() assert_glerror() // stop_glerror is still needed on OS X but has performance implications -// use macro below to conditionally add stop_glerror to non-release builds +// use macro below to conditionally add stop_glerror to non-release builds // on OS X #if LL_DARWIN && !LL_RELEASE_FOR_DOWNLOAD #define STOP_GLERROR stop_glerror() -#else +#else #define STOP_GLERROR #endif diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index ba745e0fca..45abb695cb 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -384,7 +384,7 @@ void LLGLSLShader::unloadInternal() bool LLGLSLShader::createShader() { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - + unloadInternal(); sInstances.insert(this); @@ -968,7 +968,7 @@ bool LLGLSLShader::mapUniforms() glUniformBlockBinding(mProgramObject, UBOBlockIndex, i); } } - + unbind(); LL_DEBUGS("ShaderUniform") << "Total Uniform Size: " << mTotalUniformSize << LL_ENDL; diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 3b4224cbfd..9339e7998d 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -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 mGLTFVariants; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 9e69f565f6..ac3811b5de 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -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) diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index f50213f5ab..a6d0fb791b 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -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) diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 165b668b76..8b0e8c327f 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -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) diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 913dc32574..3dd8bb7968 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -317,7 +317,7 @@ public: { //allocate a new buffer LL_PROFILE_GPU_ZONE("vbo alloc"); - // ON OS X, we don't allocate a VBO until the last possible moment + // ON OS X, we don't allocate a VBO until the last possible moment // in unmapBuffer data = (U8*) ll_aligned_malloc_16(size); STOP_GLERROR; @@ -329,12 +329,12 @@ public: LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER); llassert(size >= 2); - + if (data) { ll_aligned_free_16(data); } - + mAllocated -= size; STOP_GLERROR; if (name) @@ -1517,7 +1517,7 @@ void LLVertexBuffer::setBuffer() // no data may be pending llassert(mMappedVertexRegions.empty()); llassert(mMappedIndexRegions.empty()); - + // a shader must be bound llassert(LLGLSLShader::sCurBoundShaderPtr); @@ -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 diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 76ef5570eb..ed6b3da257 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -110,7 +110,7 @@ public: TYPE_WEIGHT, // "weight" TYPE_WEIGHT4, // "weight4" TYPE_CLOTHWEIGHT, // "clothing" - TYPE_JOINT, // "joint" + TYPE_JOINT, // "joint" TYPE_TEXTURE_INDEX, // "texture_index" TYPE_MAX, // TYPE_MAX is the size/boundary marker for attributes that go in the vertex buffer TYPE_INDEX, // TYPE_INDEX is beyond _MAX because it lives in a separate (index) buffer @@ -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); diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl index 7c110c57f2..2cb7ff196b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl @@ -153,7 +153,7 @@ float terrain_mix(TerrainMix tm, vec4 tms4); vec3 mikktspace(vec3 vNt, vec3 vT) { vec3 vN = vary_normal; - + vec3 vB = vary_sign * cross(vN, vT); vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl index d71a3fad99..789c00259b 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl @@ -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 diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl index f123c29101..aac3dc917f 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl @@ -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; + +#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 - normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0); - metallic_roughness_texcoord = texture_transform(texcoord0, texture_metallic_roughness_transform, texture_matrix0); + 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 diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp index 9f1cb0c1cd..2ef9237f2d 100644 --- a/indra/newview/gltf/accessor.cpp +++ b/indra/newview/gltf/accessor.cpp @@ -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; diff --git a/indra/newview/gltf/animation.cpp b/indra/newview/gltf/animation.cpp index 47c2284038..8b85eba3e5 100644 --- a/indra/newview/gltf/animation.cpp +++ b/indra/newview/gltf/animation.cpp @@ -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(max_joints, mJoints.size()); std::vector t_mp; diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index a4efb25860..21be69aae2 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -45,7 +45,8 @@ namespace LL namespace GLTF { static std::unordered_set 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); diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index 8f28e5905f..ea3f7d480a 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -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; }; diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index c26752a6b6..40f9448aaf 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -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 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(ec); if (ec) return false; + t.y = arr[1].to_number(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) diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index e6946a3c90..2280c7004e 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -42,30 +42,45 @@ using namespace boost::json; // Mesh data useful for Mikktspace tangent generation (and flat normal generation) struct MikktMesh { - std::vector p; - std::vector n; - std::vector tc; - std::vector w; - std::vector t; - std::vector c; - std::vector j; + std::vector p; //positions + std::vector n; //normals + std::vector t; //tangents + std::vector tc0; //texcoords 0 + std::vector tc1; //texcoords 1 + std::vector c; //colors + std::vector w; //weights + std::vector 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 (has_normals) + if (prim->mMode == Primitive::Mode::TRIANGLES) { - n[i].set(prim->mNormals[idx].getF32ptr()); + 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 (rigged) + if (indexed) { - w[i].set(prim->mWeights[idx].getF32ptr()); - j[i] = prim->mJoints[idx]; + 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[v]].getF32ptr()); + } + + if (rigged) + { + 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 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 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,7 +237,11 @@ 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()); for (int i = 0; i < remap.size(); ++i) @@ -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& 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,10 +559,13 @@ bool Primitive::prep(Asset& asset) mVertexBuffer->unbind(); - Material& material = asset.mMaterials[mMaterial]; - if (material.mAlphaMode == Material::AlphaMode::BLEND) + if (mMaterial != INVALID_INDEX) { - mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND; + 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); diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h index f9d7c63c65..7cc05cf831 100644 --- a/indra/newview/gltf/primitive.h +++ b/indra/newview/gltf/primitive.h @@ -58,7 +58,8 @@ namespace LL LLPointer mVertexBuffer; // CPU copy of mesh data, keep these as LLVector types for compatibility with raycasting code - std::vector mTexCoords; + std::vector mTexCoords0; + std::vector mTexCoords1; std::vector mNormals; std::vector mTangents; std::vector mPositions; diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 54cef0e10b..d933624a9b 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -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()); } } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index ce6799ec92..8f42d7c71e 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -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); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 6224b611c2..f6fe0458b0 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -1973,7 +1973,7 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) LL_DEBUGS() << "no region set" << LL_ENDL; getChild("region_text")->setValue(LLSD("")); } - + // Update visibility of terrain swatches, etc refresh(); @@ -2115,7 +2115,7 @@ bool LLPanelRegionTerrainInfo::sendUpdate() for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i) { LLPointer mat_override = new LLGLTFMaterial(); - + const bool transform_controls_valid = mMaterialScaleUCtrl[i] && mMaterialScaleVCtrl[i] && mMaterialRotationCtrl[i] && mMaterialOffsetUCtrl[i] && mMaterialOffsetVCtrl[i]; if (transform_controls_valid) { diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index a2cfd2ea1d..d3b9fea4c9 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -1,4 +1,4 @@ -/** +/** * @file llfloaterregioninfo.h * @author Aaron Brashears * @brief Declaration of the region info and controls floater and panels. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -108,14 +108,14 @@ public: // from LLPanel void refresh() override; - + void onRegionChanged(); void requestRegionInfo(); void enableTopButtons(); void disableTopButtons(); private: - + LLFloaterRegionInfo(const LLSD& seed); ~LLFloaterRegionInfo(); @@ -144,31 +144,31 @@ class LLPanelRegionInfo : public LLPanel { public: LLPanelRegionInfo(); - + void onBtnSet(); void onChangeChildCtrl(LLUICtrl* ctrl); void onChangeAnything(); static void onChangeText(LLLineEditor* caller, void* user_data); - + virtual bool refreshFromRegion(LLViewerRegion* region); virtual bool estateUpdate(LLMessageSystem* msg) { return true; } - + bool postBuild() override; virtual void updateChild(LLUICtrl* child_ctrl); - + void enableButton(const std::string& btn_name, bool enable = true); void disableButton(const std::string& btn_name); - + void onClickManageTelehub(); - + protected: void initCtrl(const std::string& name); template void initAndSetCtrl(CTRL*& ctrl, const std::string& name); - + // Returns true if update sent and apply button should be // disabled. virtual bool sendUpdate() { return true; } - + typedef std::vector strings_t; //typedef std::vector integers_t; void sendEstateOwnerMessage( @@ -176,8 +176,8 @@ protected: const std::string& request, const LLUUID& invoice, const strings_t& strings); - - + + // member data LLHost mHost; }; @@ -208,16 +208,16 @@ protected: class LLPanelRegionGeneralInfo : public LLPanelRegionInfo { - + public: LLPanelRegionGeneralInfo() : LLPanelRegionInfo() {} ~LLPanelRegionGeneralInfo() {} - + bool refreshFromRegion(LLViewerRegion* region) override; - + bool postBuild() override; - + void onBtnSet(); void setObjBonusFactor(F32 object_bonus_factor) {mObjBonusFactor = object_bonus_factor;} @@ -245,9 +245,9 @@ public: ~LLPanelRegionDebugInfo() {} bool postBuild() override; - + bool refreshFromRegion(LLViewerRegion* region) override; - + protected: bool sendUpdate() override; @@ -261,7 +261,7 @@ protected: bool callbackRestart(const LLSD& notification, const LLSD& response, const LLSD& seconds); // Ansariel, added seconds for FIRE-1073 static void onClickCancelRestart(void* data); static void onClickDebugConsole(void* data); - + private: LLUUID mTargetAvatar; }; @@ -275,9 +275,9 @@ class LLPanelRegionTerrainInfo : public LLPanelRegionInfo public: LLPanelRegionTerrainInfo(); ~LLPanelRegionTerrainInfo() {} - + bool postBuild() override; - + bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator void setEnvControls(bool available); // Whether environment settings are available for this region @@ -286,7 +286,7 @@ public: bool validateTextureHeights(); //static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button - + void onSelectMaterialType(); void updateForMaterialType(); @@ -326,13 +326,13 @@ class LLPanelEstateInfo : public LLPanelRegionInfo { public: static void initDispatch(LLDispatcher& dispatch); - + void onChangeFixedSun(); void onChangeUseGlobalTime(); void onChangeAccessOverride(); - + void onClickEditSky(); - void onClickEditSkyHelp(); + void onClickEditSkyHelp(); void onClickEditDayCycle(); void onClickEditDayCycleHelp(); @@ -344,26 +344,26 @@ public: void onKickUserCommit(const uuid_vec_t& ids); static void onClickMessageEstate(void* data); bool onMessageCommit(const LLSD& notification, const LLSD& response); - + LLPanelEstateInfo(); ~LLPanelEstateInfo() {} - + void updateControls(LLViewerRegion* region); - + static void updateEstateName(const std::string& name); static void updateEstateOwnerName(const std::string& name); bool refreshFromRegion(LLViewerRegion* region) override; bool estateUpdate(LLMessageSystem* msg) override; - + bool postBuild() override; void updateChild(LLUICtrl* child_ctrl) override; void refresh() override; void refreshFromEstate(); - + static bool isLindenEstate(); - + const std::string getOwnerName() const; void setOwnerName(const std::string& name); @@ -374,7 +374,7 @@ protected: void commitEstateAccess(); void commitEstateManagers(); - + bool checkSunHourSlider(LLUICtrl* child_ctrl); U32 mEstateID; @@ -387,7 +387,7 @@ class LLPanelEstateCovenant : public LLPanelRegionInfo public: LLPanelEstateCovenant(); ~LLPanelEstateCovenant() {} - + bool postBuild() override; void updateChild(LLUICtrl* child_ctrl) override; bool refreshFromRegion(LLViewerRegion* region) override; @@ -450,7 +450,7 @@ class LLPanelRegionExperiences : public LLPanelRegionInfo public: LLPanelRegionExperiences(){} bool postBuild() override; - + static bool experienceCoreConfirm(const LLSD& notification, const LLSD& response); static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id); @@ -515,7 +515,7 @@ private: void onAllowedSearchEdit(const std::string& search_string); void onAllowedGroupsSearchEdit(const std::string& search_string); void onBannedSearchEdit(const std::string& search_string); - + // Group picker callback is different, can't use core methods below bool addAllowedGroup(const LLSD& notification, const LLSD& response); void addAllowedGroup2(LLUUID id); diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp index c1ab28dd23..f544b70329 100644 --- a/indra/newview/llheroprobemanager.cpp +++ b/indra/newview/llheroprobemanager.cpp @@ -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() diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 8e94c4bced..cd4aaea2de 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -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()); }); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 3eec19ddd5..e047721c23 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -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) diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp index bf19325abc..7131ce3e8a 100644 --- a/indra/newview/lltinygltfhelper.cpp +++ b/indra/newview/lltinygltfhelper.cpp @@ -264,12 +264,12 @@ bool LLTinyGLTFHelper::saveModel(const std::string& filename, tinygltf::Model& m std::string filename_lc = filename; LLStringUtil::toLower(filename_lc); - + bool embed_images = false; bool embed_buffers = false; bool pretty_print = true; bool write_binary = false; - + if (std::string::npos == filename_lc.rfind(".gltf")) { // file is binary diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 6a31cdf695..c677abc430 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -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; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 62a629f66b..82e6c8f62d 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -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; } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 6eca81e802..3486d8806c 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -349,7 +349,7 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); } -//static +//static LLImageRaw* LLViewerTextureManager::getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype) { return gTextureList.getRawImageFromMemory(data, size, mimetype); diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 51725a553d..a21d65286d 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -197,7 +197,7 @@ private: // PoundLife - Improved Object Inspect LLGLenum primary_format = 0, const LLUUID& force_id = LLUUID::null ); - + LLImageRaw* getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype); LLViewerFetchedTexture* getImageFromMemory(const U8* data, U32 size, std::string_view mimetype); diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index a098bb7f01..d661caa76e 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llvlcomposition.cpp * @brief Viewer-side representation of a composition layer... * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -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(); @@ -471,7 +470,7 @@ bool LLVLComposition::generateHeights(const F32 x, const F32 y, llassert(mSurfacep); - if (!mSurfacep || !mSurfacep->getRegion()) + if (!mSurfacep || !mSurfacep->getRegion()) { // We don't always have the region yet here.... return false; @@ -542,7 +541,7 @@ bool LLVLComposition::generateHeights(const F32 x, const F32 y, vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv; vec[2] = height*zScaleInv; // - // Choose material value by adding to the exact height a random value + // Choose material value by adding to the exact height a random value // vec1[0] = vec[0]*(0.2222222222f); vec1[1] = vec[1]*(0.2222222222f); @@ -989,7 +988,7 @@ bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y, { unboost_minimap_material(mDetailMaterials[i]); } - + return true; } diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index a003f74eda..763ff69442 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -1,25 +1,25 @@ -/** +/** * @file llvlcomposition.h * @brief Viewer-side representation of a composition layer... * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -115,8 +115,7 @@ public: bool generateHeights(const F32 x, const F32 y, const F32 width, const F32 height); 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); + bool generateMinimapTileLand(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 diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 72dfd71b35..762359389c 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -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. diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 2a184ae066..eac9471e1a 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -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() diff --git a/indra/newview/skins/default/xui/en/panel_region_terrain_texture_transform.xml b/indra/newview/skins/default/xui/en/panel_region_terrain_texture_transform.xml index cbcbe418cd..9a90700056 100644 --- a/indra/newview/skins/default/xui/en/panel_region_terrain_texture_transform.xml +++ b/indra/newview/skins/default/xui/en/panel_region_terrain_texture_transform.xml @@ -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"> diff --git a/indra/newview/skins/default/xui/en/panel_settings_terrain_transform.xml b/indra/newview/skins/default/xui/en/panel_settings_terrain_transform.xml index 7052622813..0bf0d8cffc 100644 --- a/indra/newview/skins/default/xui/en/panel_settings_terrain_transform.xml +++ b/indra/newview/skins/default/xui/en/panel_settings_terrain_transform.xml @@ -7,6 +7,62 @@ left="0" name="panel_settings_terrain_transform" top="0"> + + 1 + + + 2 + + + 3 + + + 4 + Scale u - + Scale v - + Rotation - + Offset y - + Offset v - +