diff options
26 files changed, 848 insertions, 136 deletions
| diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index bc542d325e..512ef340f9 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1409,6 +1409,7 @@ void LLShaderMgr::initAttribsAndUniforms()      mReservedUniforms.push_back("detail_3");      mReservedUniforms.push_back("alpha_ramp"); +    mReservedUniforms.push_back("paint_map");      mReservedUniforms.push_back("detail_0_base_color");      mReservedUniforms.push_back("detail_1_base_color"); @@ -1433,6 +1434,8 @@ void LLShaderMgr::initAttribsAndUniforms()      mReservedUniforms.push_back("emissiveColors");      mReservedUniforms.push_back("minimum_alphas"); +    mReservedUniforms.push_back("region_scale"); +      mReservedUniforms.push_back("origin");      mReservedUniforms.push_back("display_gamma"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 921ef20997..2b76ef664b 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -267,6 +267,7 @@ public:          TERRAIN_DETAIL3,                    //  "detail_3"          TERRAIN_ALPHARAMP,                  //  "alpha_ramp" +        TERRAIN_PAINTMAP,                   //  "paint_map"          TERRAIN_DETAIL0_BASE_COLOR,                //  "detail_0_base_color" (GLTF)          TERRAIN_DETAIL1_BASE_COLOR,                //  "detail_1_base_color" (GLTF) @@ -291,6 +292,8 @@ public:          TERRAIN_EMISSIVE_COLORS,                   //  "emissiveColors" (GLTF)          TERRAIN_MINIMUM_ALPHAS,                    //  "minimum_alphas" (GLTF) +        REGION_SCALE,                              //  "region_scale" (GLTF) +          SHINY_ORIGIN,                       //  "origin"          DISPLAY_GAMMA,                      //  "display_gamma" diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index a34354d287..e7857ff09f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -578,6 +578,7 @@ set(viewer_SOURCE_FILES      llsyswellwindow.cpp      llteleporthistory.cpp      llteleporthistorystorage.cpp +    llterrainpaintmap.cpp      lltexturecache.cpp      lltexturectrl.cpp      lltexturefetch.cpp @@ -1235,6 +1236,7 @@ set(viewer_HEADER_FILES      lltable.h      llteleporthistory.h      llteleporthistorystorage.h +    llterrainpaintmap.h      lltexturecache.h      lltexturectrl.h      lltexturefetch.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9e5d3f09bd..5c3706bb6c 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -14966,6 +14966,39 @@        <key>Value</key>        <real>0.0</real>      </map> +    <key>LocalTerrainPaintEnabled</key> +    <map> +      <key>Comment</key> +      <string>Enables local paintmap if LocalTerrainAsset1, etc are set</string> +      <key>Persist</key> +      <integer>0</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>0</integer> +    </map> +    <key>TerrainPaintBitDepth</key> +    <map> +      <key>Comment</key> +      <string>Bit depth for future terrain paint map operations. Min: 1. Max: 8. Takes effect when the paint map is created or modified. Modifications to an existing paintmap of different bit depth will have lower precision.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>U32</string> +      <key>Value</key> +      <integer>5</integer> +    </map> +    <key>TerrainPaintResolution</key> +    <map> +      <key>Comment</key> +      <string>Resolution of the terrain paint map in pixels. Rounded to a power of two. Min: 16. Max: RenderMaxTextureResolution. Takes effect when the paint map is created.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>U32</string> +      <key>Value</key> +      <integer>2048</integer> +    </map>  	<key>PathfindingRetrieveNeighboringRegion</key>      <map>        <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl index 6ca35419f2..410c447c64 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl @@ -30,6 +30,9 @@  #define TERRAIN_PBR_DETAIL_NORMAL -2  #define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 +#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0 +#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1 +  #if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3  #define TerrainCoord vec4[3]  #elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 @@ -48,6 +51,7 @@ struct TerrainMix  };  TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal); +TerrainMix get_terrain_usage_from_weight3(vec3 weight3);  struct PBRMix  { @@ -97,7 +101,11 @@ PBRMix mix_pbr(PBRMix mix1, PBRMix mix2, float mix2_weight);  out vec4 frag_data[4]; +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE  uniform sampler2D alpha_ramp; +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +uniform sampler2D paint_map; +#endif  // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#additional-textures  uniform sampler2D detail_0_base_color; @@ -133,19 +141,25 @@ uniform vec3[4] emissiveColors;  #endif  uniform vec4 minimum_alphas; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() -#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 -in vec4[10] vary_coords; -#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 -in vec4[2] vary_coords; -#endif  in vec3 vary_position;  in vec3 vary_normal;  #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)  in vec3 vary_tangents[4];  flat in float vary_signs[4];  #endif + +// vary_texcoord* are used for terrain composition, vary_coords are used for terrain UVs +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE  in vec4 vary_texcoord0;  in vec4 vary_texcoord1; +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +in vec2 vary_texcoord; +#endif +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +in vec4[10] vary_coords; +#elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1 +in vec4[2] vary_coords; +#endif  void mirrorClip(vec3 position); @@ -171,11 +185,16 @@ void main()      // Make sure we clip the terrain if we're in a mirror.      mirrorClip(vary_position); +    TerrainMix tm; +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE      float alpha1 = texture(alpha_ramp, vary_texcoord0.zw).a;      float alpha2 = texture(alpha_ramp,vary_texcoord1.xy).a;      float alphaFinal = texture(alpha_ramp, vary_texcoord1.zw).a; -    TerrainMix tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal); +    tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal); +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +    tm = get_terrain_usage_from_weight3(texture(paint_map, vary_texcoord).xyz); +#endif  #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)      // RGB = Occlusion, Roughness, Metal diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl index 5098de717e..dc43007dca 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainUtilF.glsl @@ -51,7 +51,12 @@  #define TERRAIN_PBR_DETAIL_NORMAL -2  #define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 +#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0 +#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1 + +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3  in vec3 vary_vertex_normal; +#endif  vec3 srgb_to_linear(vec3 c); @@ -202,6 +207,45 @@ TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal)      return tm;  } +// A paintmap weight applier for 4 swatches. The input saves a channel by not +// storing swatch 1, and assuming the weights of the 4 swatches add to 1. +// The components of weight3 should be between 0 and 1 +// The sum of the components of weight3 should be between 0 and 1 +TerrainMix get_terrain_usage_from_weight3(vec3 weight3) +{ +    // These steps ensure the output weights add to between 0 and 1 +    weight3.xyz = max(vec3(0.0), weight3.xyz); +    weight3.xyz /= max(1.0, weight3.x + weight3.y + weight3.z); + +    TerrainMix tm; + +    // Extract the first weight from the other weights +    tm.weight.x = 1.0 - (weight3.x + weight3.y + weight3.z); +    tm.weight.yzw = weight3.xyz; +    ivec4 usage = max(ivec4(0), ivec4(ceil(tm.weight))); + +    tm.type = (usage.x * MIX_X) | +              (usage.y * MIX_Y) | +              (usage.z * MIX_Z) | +              (usage.w * MIX_W); +    return tm; +} + +// Inverse of get_terrain_usage_from_weight3, excluding usage flags +// The components of weight should be between 0 and 1 +// The sum of the components of weight should be 1 +vec3 get_weight3_from_terrain_weight(vec4 weight) +{ +    // These steps ensure the input weights add to 1 +    weight = max(vec4(0.0), weight); +    weight.x += 1.0 - sign(weight.x + weight.y + weight.z + weight.w); +    weight /= weight.x + weight.y + weight.z + weight.w; + +    // Then return the input weights with the first weight truncated +    return weight.yzw; +} + +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3  TerrainTriplanar _t_triplanar()  {      float sharpness = TERRAIN_TRIPLANAR_BLEND_FACTOR; @@ -219,6 +263,8 @@ TerrainTriplanar _t_triplanar()                ((usage.z) * SAMPLE_Z);      return tw;  } +#endif +  // Assume weights add to 1  float terrain_mix(TerrainMix tm, vec4 tms4) diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl index c90b2b5926..6791a22a76 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainV.glsl @@ -28,31 +28,47 @@  #define TERRAIN_PBR_DETAIL_NORMAL -2  #define TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS -3 +#define TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE 0 +#define TERRAIN_PAINT_TYPE_PBR_PAINTMAP 1 +  uniform mat3 normal_matrix;  uniform mat4 texture_matrix0;  uniform mat4 modelview_matrix;  uniform mat4 modelview_projection_matrix; +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +uniform float region_scale; +#endif  in vec3 position;  in vec3 normal;  in vec4 tangent;  in vec4 diffuse_color; +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE  in vec2 texcoord1; +#endif -out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl +out vec3 vary_position;  out vec3 vary_normal; +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3 +out vec3 vary_vertex_normal; // Used by pbrterrainUtilF.glsl +#endif  #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)  out vec3 vary_tangents[4];  flat out float vary_signs[4];  #endif + +// vary_texcoord* are used for terrain composition, vary_coords are used for terrain UVs +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE  out vec4 vary_texcoord0;  out vec4 vary_texcoord1; +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +out vec2 vary_texcoord; +#endif  #if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3  out vec4[10] vary_coords;  #elif TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 1  out vec4[2] vary_coords;  #endif -out vec3 vary_position;  // *HACK: Each material uses only one texture transform, but the KHR texture  // transform spec allows handling texture transforms separately for each @@ -69,7 +85,9 @@ void main()      vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;      vec3 n = normal_matrix * normal; +#if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3      vary_vertex_normal = normal; +#endif      vec3 t = normal_matrix * tangent.xyz;  #if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL) @@ -110,9 +128,9 @@ void main()      // Transform and pass tex coords      {          vec4[2] ttt; +#define transform_xy()             terrain_texture_transform(position.xy,               ttt)  #if TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT == 3  // Don't care about upside-down (transform_xy_flipped()) -#define transform_xy()             terrain_texture_transform(position.xy,               ttt)  #define transform_yz()             terrain_texture_transform(position.yz,               ttt)  #define transform_negx_z()         terrain_texture_transform(position.xz * vec2(-1, 1), ttt)  #define transform_yz_flipped()     terrain_texture_transform(position.yz * vec2(-1, 1), ttt) @@ -157,26 +175,30 @@ void main()          ttt[0].xyz = terrain_texture_transforms[0].xyz;          ttt[1].x = terrain_texture_transforms[0].w;          ttt[1].y = terrain_texture_transforms[1].x; -        vary_coords[0].xy = terrain_texture_transform(position.xy, ttt); +        vary_coords[0].xy = transform_xy();          // material 2          ttt[0].xyz = terrain_texture_transforms[1].yzw;          ttt[1].xy = terrain_texture_transforms[2].xy; -        vary_coords[0].zw = terrain_texture_transform(position.xy, ttt); +        vary_coords[0].zw = transform_xy();          // material 3          ttt[0].xy = terrain_texture_transforms[2].zw;          ttt[0].z = terrain_texture_transforms[3].x;          ttt[1].xy = terrain_texture_transforms[3].yz; -        vary_coords[1].xy = terrain_texture_transform(position.xy, ttt); +        vary_coords[1].xy = transform_xy();          // material 4          ttt[0].x = terrain_texture_transforms[3].w;          ttt[0].yz = terrain_texture_transforms[4].xy;          ttt[1].xy = terrain_texture_transforms[4].zw; -        vary_coords[1].zw = terrain_texture_transform(position.xy, ttt); +        vary_coords[1].zw = transform_xy();  #endif      } -    vec4 tc = vec4(texcoord1,0,1); +#if TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE +    vec2 tc = texcoord1.xy;      vary_texcoord0.zw = tc.xy;      vary_texcoord1.xy = tc.xy-vec2(2.0, 0.0);      vary_texcoord1.zw = tc.xy-vec2(1.0, 0.0); +#elif TERRAIN_PAINT_TYPE == TERRAIN_PAINT_TYPE_PBR_PAINTMAP +    vary_texcoord = position.xy / region_scale; +#endif  } diff --git a/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl new file mode 100644 index 0000000000..cf20653a0f --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeF.glsl @@ -0,0 +1,62 @@ +/** + * @file terrainBakeF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +out vec4 frag_color; + +struct TerrainMix +{ +    vec4 weight; +    int type; +}; + +TerrainMix get_terrain_mix_weights(float alpha1, float alpha2, float alphaFinal); + +uniform sampler2D alpha_ramp; + +// vary_texcoord* are used for terrain composition +in vec4 vary_texcoord0; +in vec4 vary_texcoord1; + +void main() +{ +    TerrainMix tm; +    float alpha1 = texture(alpha_ramp, vary_texcoord0.zw).a; +    float alpha2 = texture(alpha_ramp,vary_texcoord1.xy).a; +    float alphaFinal = texture(alpha_ramp, vary_texcoord1.zw).a; + +    tm = get_terrain_mix_weights(alpha1, alpha2, alphaFinal); + +    // tm.weight.x can be ignored. The paintmap saves a channel by not storing +    // swatch 1, and assuming the weights of the 4 swatches add to 1. +    // TERRAIN_PAINT_PRECISION emulates loss of precision at lower bit depth +    // when a corresponding low-bit image format is not available. Because +    // integral values at one depth cannot be precisely represented at another +    // bit depth, rounding is required. To maximize numerical stability for +    // future conversions, bit depth conversions should round to the nearest +    // integer, not floor or ceil. +    frag_color = max(vec4(round(tm.weight.yzw * TERRAIN_PAINT_PRECISION) / TERRAIN_PAINT_PRECISION, 1.0), vec4(0)); +} diff --git a/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeV.glsl b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeV.glsl new file mode 100644 index 0000000000..fd150b54ad --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/pbrTerrainBakeV.glsl @@ -0,0 +1,42 @@ +/** + * @file pbrTerrainBakeV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +uniform mat4 modelview_projection_matrix; + +in vec3 position; +in vec2 texcoord1; + +out vec4 vary_texcoord0; +out vec4 vary_texcoord1; + +void main() +{ +    gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); +    vec2 tc = texcoord1.xy; +    vary_texcoord0.zw = tc.xy; +    vary_texcoord1.xy = tc.xy-vec2(2.0, 0.0); +    vary_texcoord1.zw = tc.xy-vec2(1.0, 0.0); +} + diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 7d2912d81f..5e676bc5b3 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -219,7 +219,9 @@ void LLDrawPoolTerrain::renderFullShader()      else      {          // Use materials -        sShader = &gDeferredPBRTerrainProgram; +        U32 paint_type = use_local_materials ? gLocalTerrainMaterials.getPaintType() : compp->getPaintType(); +        paint_type = llclamp(paint_type, 0, TERRAIN_PAINT_TYPE_COUNT); +        sShader = &gDeferredPBRTerrainProgram[paint_type];          sShader->bind();          renderFullShaderPBR(use_local_materials);      } @@ -326,7 +328,7 @@ void LLDrawPoolTerrain::renderFullShaderTextures()  }  // *TODO: Investigate use of bindFast for PBR terrain textures -void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials) +void LLDrawPoolTerrain::renderFullShaderPBR(bool use_local_materials)  {      // Hack! Get the region that this draw pool is rendering from!      LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); @@ -339,7 +341,7 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)      llassert(shader_material_count == terrain_material_count);  #endif -    if (local_materials) +    if (use_local_materials)      {          // Override region terrain with the global local override terrain          fetched_materials = &gLocalTerrainMaterials.mDetailRenderMaterials; @@ -351,6 +353,9 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)          if (!materials[i]) { materials[i] = &LLGLTFMaterial::sDefault; }      } +    U32 paint_type = use_local_materials ? gLocalTerrainMaterials.getPaintType() : compp->getPaintType(); +    paint_type = llclamp(paint_type, 0, TERRAIN_PAINT_TYPE_COUNT); +      S32 detail_basecolor[terrain_material_count];      S32 detail_normal[terrain_material_count];      S32 detail_metalrough[terrain_material_count]; @@ -481,11 +486,31 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)      LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();      // -    // Alpha Ramp +    // Alpha Ramp or paint map      // -    S32 alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); -    gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep); -    gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); +    S32 alpha_ramp = -1; +    S32 paint_map = -1; +    if (paint_type == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE) +    { +        alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); +        gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep); +        gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); +    } +    else if (paint_type == TERRAIN_PAINT_TYPE_PBR_PAINTMAP) +    { +        paint_map = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_PAINTMAP); +        LLViewerTexture* tex_paint_map = use_local_materials ? gLocalTerrainMaterials.getPaintMap() : compp->getPaintMap(); +        // If no paintmap is available, fall back to rendering just material slot 1 (by binding the appropriate image) +        if (!tex_paint_map) { tex_paint_map = LLViewerTexture::sBlackImagep.get(); } +        // This is a paint map for four materials, but we save a channel by +        // storing the paintmap as the "difference" between slot 1 and the +        // other 3 slots. +        llassert(tex_paint_map->getComponents() == 3); +        gGL.getTexUnit(paint_map)->bind(tex_paint_map); +        gGL.getTexUnit(paint_map)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + +        shader->uniform1f(LLShaderMgr::REGION_SCALE, regionp->getWidth()); +    }      //      // GLTF uniforms @@ -534,11 +559,22 @@ void LLDrawPoolTerrain::renderFullShaderPBR(bool local_materials)      // Disable multitexture -    sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); +    if (paint_type == TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE) +    { +        sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); -    gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE); -    gGL.getTexUnit(alpha_ramp)->disable(); -    gGL.getTexUnit(alpha_ramp)->activate(); +        gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE); +        gGL.getTexUnit(alpha_ramp)->disable(); +        gGL.getTexUnit(alpha_ramp)->activate(); +    } +    else if (paint_type == TERRAIN_PAINT_TYPE_PBR_PAINTMAP) +    { +        sShader->disableTexture(LLViewerShaderMgr::TERRAIN_PAINTMAP); + +        gGL.getTexUnit(paint_map)->unbind(LLTexUnit::TT_TEXTURE); +        gGL.getTexUnit(paint_map)->disable(); +        gGL.getTexUnit(paint_map)->activate(); +    }      for (U32 i = 0; i < terrain_material_count; ++i)      { diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index a8097fb58b..5380463d01 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -38,7 +38,6 @@ public:          VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX |                      LLVertexBuffer::MAP_NORMAL |                      LLVertexBuffer::MAP_TANGENT | // Only PBR terrain uses this currently -                    LLVertexBuffer::MAP_TEXCOORD0 |                      LLVertexBuffer::MAP_TEXCOORD1      }; @@ -80,7 +79,7 @@ protected:      void renderFull4TU();      void renderFullShader();      void renderFullShaderTextures(); -    void renderFullShaderPBR(bool local_materials = false); +    void renderFullShaderPBR(bool use_local_materials = false);      void drawLoop();  private: diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h index 68295225b6..10a104730b 100644 --- a/indra/newview/llsurface.h +++ b/indra/newview/llsurface.h @@ -110,6 +110,7 @@ public:      LLSurfacePatch *resolvePatchRegion(const F32 x, const F32 y) const;      LLSurfacePatch *resolvePatchRegion(const LLVector3 &position_region) const;      LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const; +    LLSurfacePatch *getPatch(const S32 x, const S32 y) const;      // Update methods (called during idle, normally)      template<bool PBR> @@ -176,8 +177,6 @@ protected:      void createPatchData();     // Allocates memory for patches.      void destroyPatchData();    // Deallocates memory for patches. -    LLSurfacePatch *getPatch(const S32 x, const S32 y) const; -  protected:      LLVector3d  mOriginGlobal;      // In absolute frame      LLSurfacePatch *mPatchList;     // Array of all patches diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 0550889a9b..4315c4c6b0 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -201,13 +201,13 @@ LLVector2 LLSurfacePatch::getTexCoords(const U32 x, const U32 y) const  void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 *vertex, LLVector3 *normal, -                          LLVector2 *tex0, LLVector2 *tex1) +                          LLVector2 *tex1) const  {      if (!mSurfacep || !mSurfacep->getRegion() || !mSurfacep->getGridsPerEdge() || !mVObjp)      {          return; // failsafe      } -    llassert_always(vertex && normal && tex0 && tex1); +    llassert_always(vertex && normal && tex1);      U32 surface_stride = mSurfacep->getGridsPerEdge();      U32 point_offset = x + y*surface_stride; @@ -220,12 +220,6 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3      pos_agent.mV[VZ]  = *(mDataZ + point_offset);      *vertex     = pos_agent-mVObjp->getRegion()->getOriginAgent(); -    LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent(); -    // *NOTE: Only PBR terrain uses the UVs right now. Texture terrain just ignores it. -    // *NOTE: In the future, UVs and horizontal position will no longer have a 1:1 relationship for PBR terrain -    LLVector3 tex_pos = rel_pos; -    tex0->mV[0]  = tex_pos.mV[0]; -    tex0->mV[1]  = tex_pos.mV[1];      tex1->mV[0] = mSurfacep->getRegion()->getCompositionXY(llfloor(mOriginRegion.mV[0])+x, llfloor(mOriginRegion.mV[1])+y);      const F32 xyScale = 4.9215f*7.f; //0.93284f; diff --git a/indra/newview/llsurfacepatch.h b/indra/newview/llsurfacepatch.h index 195250d2c0..f4831487c1 100644 --- a/indra/newview/llsurfacepatch.h +++ b/indra/newview/llsurfacepatch.h @@ -116,7 +116,7 @@ public:      void calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index /* 0 or 1 */);      void eval(const U32 x, const U32 y, const U32 stride, -                LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex0, LLVector2 *tex1); +                LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex1) const; @@ -146,6 +146,8 @@ public:      void dirty();           // Mark this surface patch as dirty...      void clearDirty()                           { mDirty = false; } +    bool isHeightsGenerated() const { return mHeightsGenerated; } +      void clearVObj();  public: diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp new file mode 100644 index 0000000000..4381d14546 --- /dev/null +++ b/indra/newview/llterrainpaintmap.cpp @@ -0,0 +1,285 @@ +/** + * @file llterrainpaintmap.cpp + * @brief Utilities for managing terrain paint maps + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llterrainpaintmap.h" + +#include "llviewerprecompiledheaders.h" + +// library includes +#include "llglslshader.h" +#include "llrendertarget.h" +#include "llvertexbuffer.h" + +// newview includes +#include "llrender.h" +#include "llsurface.h" +#include "llsurfacepatch.h" +#include "llviewercamera.h" +#include "llviewerregion.h" +#include "llviewershadermgr.h" +#include "llviewertexture.h" + +// static +bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex) +{ +    llassert(tex.getComponents() == 3); +    llassert(tex.getWidth() > 0 && tex.getHeight() > 0); +    llassert(tex.getWidth() == tex.getHeight()); +    llassert(tex.getPrimaryFormat() == GL_RGB); +    llassert(tex.getGLTexture()); + +    const LLSurface& surface = region.getLand(); +    const U32 patch_count = surface.getPatchesPerEdge(); + +    // *TODO: mHeightsGenerated isn't guaranteed to be true. Assume terrain is +    // loaded for now. Would be nice to fix the loading issue or find a better +    // heuristic to determine that the terrain is sufficiently loaded. +#if 0 +    // Don't proceed if the region heightmap isn't loaded +    for (U32 rj = 0; rj < patch_count; ++rj) +    { +        for (U32 ri = 0; ri < patch_count; ++ri) +        { +            const LLSurfacePatch* patch = surface.getPatch(ri, rj); +            if (!patch->isHeightsGenerated()) +            { +                LL_WARNS() << "Region heightmap not fully loaded" << LL_ENDL; +                return false; +            } +        } +    } +#endif + +    // Bind the debug shader and render terrain to tex +    // Use a scratch render target because its dimensions may exceed the standard bake target, and this is a one-off bake +    LLRenderTarget scratch_target; +    const S32 dim = llmin(tex.getWidth(), tex.getHeight()); +    scratch_target.allocate(dim, dim, GL_RGB, false, LLTexUnit::eTextureType::TT_TEXTURE, +                                   LLTexUnit::eTextureMipGeneration::TMG_NONE); +    if (!scratch_target.isComplete()) +    { +        llassert(false); +        LL_WARNS() << "Failed to allocate render target" << LL_ENDL; +        return false; +    } +    gGL.getTexUnit(0)->disable(); +    stop_glerror(); + +    scratch_target.bindTarget(); +    glClearColor(0, 0, 0, 0); +    scratch_target.clear(); + +    // Render terrain heightmap to paint map via shader + +    // Set up viewport, camera, and orthographic projection matrix. Position +    // the camera such that the camera points straight down, and the region +    // completely covers the "screen". Since orthographic projection does not +    // distort, we arbitrarily choose the near plane and far plane to cover the +    // full span of region heights, plus a small amount of padding to account +    // for rounding errors. +    const F32 region_width = region.getWidth(); +    const F32 region_half_width = region_width / 2.0f; +    const F32 region_camera_height = surface.getMaxZ() + DEFAULT_NEAR_PLANE; +    LLViewerCamera camera; +    const LLVector3 region_center = LLVector3(region_half_width, region_half_width, 0.0) + region.getOriginAgent(); +    const LLVector3 camera_origin = LLVector3(0.0f, 0.0f, region_camera_height) + region_center; +    camera.lookAt(camera_origin, region_center, LLVector3::y_axis); +    camera.setAspect(F32(scratch_target.getHeight()) / F32(scratch_target.getWidth())); +    const LLRect texture_rect(0, scratch_target.getHeight(), scratch_target.getWidth(), 0); +    glViewport(texture_rect.mLeft, texture_rect.mBottom, texture_rect.getWidth(), texture_rect.getHeight()); +    // Manually get modelview matrix from camera orientation. +    glh::matrix4f modelview((GLfloat *) OGL_TO_CFR_ROTATION); +    GLfloat ogl_matrix[16]; +    camera.getOpenGLTransform(ogl_matrix); +    modelview *= glh::matrix4f(ogl_matrix); +    gGL.matrixMode(LLRender::MM_MODELVIEW); +    gGL.loadMatrix(modelview.m); +    // Override the projection matrix from the camera +    gGL.matrixMode(LLRender::MM_PROJECTION); +    gGL.pushMatrix(); +    gGL.loadIdentity(); +    llassert(camera_origin.mV[VZ] >= surface.getMaxZ()); +    const F32 region_high_near = camera_origin.mV[VZ] - surface.getMaxZ(); +    constexpr F32 far_plane_delta = 0.25f; +    const F32 region_low_far = camera_origin.mV[VZ] - surface.getMinZ() + far_plane_delta; +    gGL.ortho(-region_half_width, region_half_width, -region_half_width, region_half_width, region_high_near, region_low_far); +    // No need to call camera.setPerspective because we don't need the clip planes. It would be inaccurate due to the perspective rendering anyway. + +    // Need to get the full resolution vertices in order to get an accurate +    // paintmap. It's not sufficient to iterate over the surface patches, as +    // they may be at lower LODs. +    // The functionality here is a subset of +    // LLVOSurfacePatch::getTerrainGeometry. Unlike said function, we don't +    // care about stride length since we're always rendering at full +    // resolution. We also don't care about normals/tangents because those +    // don't contribute to the paintmap. +    // *NOTE: The actual getTerrainGeometry fits the terrain vertices snugly +    // under the 16-bit indices limit. For the sake of simplicity, that has not +    // been replicated here. +    std::vector<LLPointer<LLDrawInfo>> infos; +    // Vertex and index counts adapted from LLVOSurfacePatch::getGeomSizesMain, +    // with additional vertices added as we are including the north and east +    // edges here. +    const U32 patch_size = (U32)surface.getGridsPerPatchEdge(); +    constexpr U32 stride = 1; +    const U32 vert_size = (patch_size / stride) + 1; +    const U32 n = vert_size * vert_size; +    const U32 ni = 6 * (vert_size - 1) * (vert_size - 1); +    const U32 region_vertices = n * patch_count * patch_count; +    const U32 region_indices = ni * patch_count * patch_count; +    if (LLGLSLShader::sCurBoundShaderPtr == nullptr) +    { // make sure a shader is bound to satisfy mVertexBuffer->setBuffer +        gDebugProgram.bind(); +    } +    LLPointer<LLVertexBuffer> buf = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD1); +    { +        buf->allocateBuffer(region_vertices, region_indices*2); // hack double index count... TODO: find a better way to indicate 32-bit indices will be used +        buf->setBuffer(); +        U32 vertex_total = 0; +        std::vector<U32> index_array(region_indices); +        std::vector<LLVector4a> positions(region_vertices); +        std::vector<LLVector2> texcoords1(region_vertices); +        auto idx = index_array.begin(); +        auto pos = positions.begin(); +        auto tex1 = texcoords1.begin(); +        for (U32 rj = 0; rj < patch_count; ++rj) +        { +            for (U32 ri = 0; ri < patch_count; ++ri) +            { +                const U32 index_offset = vertex_total; +                for (U32 j = 0; j < (vert_size - 1); ++j) +                { +                    for (U32 i = 0; i < (vert_size - 1); ++i) +                    { +                        // y +                        //    2....3 +                        // ^  .    . +                        // |  0....1 +                        // | +                        // ------->  x +                        // +                        // triangle 1: 0,1,2 +                        // triangle 2: 1,3,2 +                        // 0: vert0 +                        // 1: vert0 + 1 +                        // 2: vert0 + vert_size +                        // 3: vert0 + vert_size + 1 +                        const U32 vert0 = index_offset + i + (j*vert_size); +                        *idx++ = vert0; +                        *idx++ = vert0 + 1; +                        *idx++ = vert0 + vert_size; +                        *idx++ = vert0 + 1; +                        *idx++ = vert0 + vert_size + 1; +                        *idx++ = vert0 + vert_size; +                    } +                } + +                const LLSurfacePatch* patch = surface.getPatch(ri, rj); +                for (U32 j = 0; j < vert_size; ++j) +                { +                    for (U32 i = 0; i < vert_size; ++i) +                    { +                        LLVector3 scratch3; +                        LLVector3 pos3; +                        LLVector2 tex1_temp; +                        patch->eval(i, j, stride, &pos3, &scratch3, &tex1_temp); +                        (*pos++).set(pos3.mV[VX], pos3.mV[VY], pos3.mV[VZ]); +                        *tex1++ = tex1_temp; +                        vertex_total++; +                    } +                } +            } +        } +        buf->setIndexData(index_array.data(), 0, (U32)index_array.size()); +        buf->setPositionData(positions.data(), 0, (U32)positions.size()); +        buf->setTexCoord1Data(texcoords1.data(), 0, (U32)texcoords1.size()); +        buf->unmapBuffer(); +        buf->unbind(); +    } + +    // Draw the region in agent space at full resolution +    { + +        LLGLSLShader::unbind(); +        // *NOTE: A theoretical non-PBR terrain bake program would be +        // *slightly* different, due the texture terrain shader not having an +        // alpha ramp threshold (TERRAIN_RAMP_MIX_THRESHOLD) +        LLGLSLShader& shader = gPBRTerrainBakeProgram; +        shader.bind(); + +        LLGLDisable stencil(GL_STENCIL_TEST); +        LLGLDisable scissor(GL_SCISSOR_TEST); +        LLGLEnable cull_face(GL_CULL_FACE); +        LLGLDepthTest depth_test(GL_FALSE, GL_FALSE, GL_ALWAYS); + +        S32 alpha_ramp = shader.enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); +        LLPointer<LLViewerTexture> alpha_ramp_texture = LLViewerTextureManager::getFetchedTexture(IMG_ALPHA_GRAD_2D); +        gGL.getTexUnit(alpha_ramp)->bind(alpha_ramp_texture); +        gGL.getTexUnit(alpha_ramp)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + +        buf->setBuffer(); +        for (U32 rj = 0; rj < patch_count; ++rj) +        { +            for (U32 ri = 0; ri < patch_count; ++ri) +            { +                const U32 patch_index = ri + (rj * patch_count); +                const U32 index_offset = ni * patch_index; +                const U32 vertex_offset = n * patch_index; +                llassert(index_offset + ni <= region_indices); +                llassert(vertex_offset + n <= region_vertices); +                buf->drawRange(LLRender::TRIANGLES, vertex_offset, vertex_offset + n - 1, ni, index_offset); +            } +        } + +        shader.disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); + +        gGL.getTexUnit(alpha_ramp)->unbind(LLTexUnit::TT_TEXTURE); +        gGL.getTexUnit(alpha_ramp)->disable(); +        gGL.getTexUnit(alpha_ramp)->activate(); + +        shader.unbind(); +    } + +    gGL.matrixMode(LLRender::MM_PROJECTION); +    gGL.popMatrix(); + +    gGL.flush(); +    LLVertexBuffer::unbind(); +    // Final step: Copy the output to the terrain paintmap +    const bool success = tex.getGLTexture()->setSubImageFromFrameBuffer(0, 0, 0, 0, dim, dim); +    if (!success) +    { +        LL_WARNS() << "Failed to copy framebuffer to paintmap" << LL_ENDL; +    } +    glGenerateMipmap(GL_TEXTURE_2D); +    stop_glerror(); + +    scratch_target.flush(); + +    LLGLSLShader::unbind(); + +    return success; +} diff --git a/indra/newview/llterrainpaintmap.h b/indra/newview/llterrainpaintmap.h new file mode 100644 index 0000000000..66827862c5 --- /dev/null +++ b/indra/newview/llterrainpaintmap.h @@ -0,0 +1,42 @@ +/** + * @file llterrainpaintmap.h + * @brief Utilities for managing terrain paint maps + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +#pragma once + +class LLViewerRegion; +class LLViewerTexture; + +class LLTerrainPaintMap +{ +public: + +    // Convert a region's heightmap and composition into a paint map texture which +    // approximates how the terrain would be rendered with the heightmap. +    // In effect, this allows converting terrain of type TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE +    // to type TERRAIN_PAINT_TYPE_PBR_PAINTMAP. +    // Returns true if successful +    static bool bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion& region, LLViewerTexture& tex); +}; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 0e1f4c09c7..c1bf31ff9a 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -719,6 +719,8 @@ void handleLocalTerrainChanged(const LLSD& newValue)          {              gLocalTerrainMaterials.setMaterialOverride(i, mat_override);          } +        const bool paint_enabled = gSavedSettings.getBOOL("LocalTerrainPaintEnabled"); +        gLocalTerrainMaterials.setPaintType(paint_enabled ? TERRAIN_PAINT_TYPE_PBR_PAINTMAP : TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE);      }  }  //////////////////////////////////////////////////////////////////////////// @@ -909,6 +911,7 @@ void settings_setup_listeners()      setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorByDistEnabled", handleUserImpostorByDistEnabledChanged);      setting_setup_signal_listener(gSavedSettings, "TuningFPSStrategy", handleFPSTuningStrategyChanged);      { +        setting_setup_signal_listener(gSavedSettings, "LocalTerrainPaintEnabled", handleLocalTerrainChanged);          const char* transform_suffixes[] = {              "ScaleU",              "ScaleV", @@ -927,6 +930,7 @@ void settings_setup_listeners()              }          }      } +    setting_setup_signal_listener(gSavedSettings, "TerrainPaintBitDepth", handleSetShaderChanged);      setting_setup_signal_listener(gSavedPerAccountSettings, "AvatarHoverOffsetZ", handleAvatarHoverOffsetChanged);  } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 0c8dd6dff9..aa14820d55 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -42,6 +42,7 @@  #include "llnotifications.h"  #include "llnotificationsutil.h"  #include "llviewereventrecorder.h" +#include "v4coloru.h"  // newview includes  #include "llagent.h" @@ -105,6 +106,7 @@  #include "llsidepanelappearance.h"  #include "llspellcheckmenuhandler.h"  #include "llstatusbar.h" +#include "llterrainpaintmap.h"  #include "lltextureview.h"  #include "lltoolbarview.h"  #include "lltoolcomp.h" @@ -122,6 +124,7 @@  #include "llviewerparcelmgr.h"  #include "llviewerstats.h"  #include "llviewerstatsrecorder.h" +#include "llvlcomposition.h"  #include "llvoavatarself.h"  #include "llvoicevivox.h"  #include "llworld.h" @@ -1387,6 +1390,65 @@ class LLAdvancedResetInterestLists : public view_listener_t  }; +///////////// +// TERRAIN // +///////////// + +class LLAdvancedRebuildTerrain : public view_listener_t +{ +    bool handleEvent(const LLSD& userdata) +    { +        gPipeline.rebuildTerrain(); +        return true; +    } +}; + +class LLAdvancedTerrainCreateLocalPaintMap : public view_listener_t +{ +    bool handleEvent(const LLSD& userdata) +    { +        LLViewerRegion* region = gAgent.getRegion(); +        if (!region) +        { +            LL_WARNS() << "Agent not in a region" << LL_ENDL; +            return false; +        } + +        U16 dim = (U16)gSavedSettings.getU32("TerrainPaintResolution"); +        // Ensure a reasonable image size of power two +        const U32 max_resolution = gSavedSettings.getU32("RenderMaxTextureResolution"); +        dim = llclamp(dim, 16, max_resolution); +        dim = 1 << U32(std::ceil(std::log2(dim))); +        LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3); +        LLPointer<LLViewerTexture> tex = LLViewerTextureManager::getLocalTexture(image_raw.get(), true); +        const bool success = LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(*region, *tex); +        // This calls gLocalTerrainMaterials.setPaintType +        gSavedSettings.setBOOL("LocalTerrainPaintEnabled", true); +        // If baking the paintmap failed, set the paintmap to nullptr. This +        // causes LLDrawPoolTerrain to use a blank paintmap instead. +        if (!success) { tex = nullptr; } +        gLocalTerrainMaterials.setPaintMap(tex); + +        return true; +    } +}; + +class LLAdvancedTerrainDeleteLocalPaintMap : public view_listener_t +{ +    bool handleEvent(const LLSD& userdata) +    { +        // This calls gLocalTerrainMaterials.setPaintType +        gSavedSettings.setBOOL("LocalTerrainPaintEnabled", false); +        gLocalTerrainMaterials.setPaintMap(nullptr); + +        return true; +    } +}; + + +///////////// + +  class LLAdvancedBuyCurrencyTest : public view_listener_t      {      bool handleEvent(const LLSD& userdata) @@ -2242,20 +2304,6 @@ class LLAdvancedPurgeShaderCache : public view_listener_t      }  }; -///////////////////// -// REBUILD TERRAIN // -///////////////////// - - -class LLAdvancedRebuildTerrain : public view_listener_t -{ -    bool handleEvent(const LLSD& userdata) -    { -        gPipeline.rebuildTerrain(); -        return true; -    } -}; -  ////////////////////  // EVENT Recorder //  /////////////////// @@ -9851,7 +9899,6 @@ void initialize_menus()      view_listener_t::addMenu(new LLAdvancedClickGLTFEdit(), "Advanced.ClickGLTFEdit");      view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow");      view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache"); -    view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");      #ifdef TOGGLE_HACKED_GODLIKE_VIEWER      view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); @@ -9868,6 +9915,11 @@ void initialize_menus()      view_listener_t::addMenu(new LLAdvancedCheckInterestList360Mode(), "Advanced.CheckInterestList360Mode");      view_listener_t::addMenu(new LLAdvancedResetInterestLists(), "Advanced.ResetInterestLists"); +    // Develop > Terrain +    view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain"); +    view_listener_t::addMenu(new LLAdvancedTerrainCreateLocalPaintMap(), "Advanced.TerrainCreateLocalPaintMap"); +    view_listener_t::addMenu(new LLAdvancedTerrainDeleteLocalPaintMap(), "Advanced.TerrainDeleteLocalPaintMap"); +      // Advanced > UI      commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2));   // sigh! this one opens the MEDIA browser      commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2));   // this one opens the Web Content floater diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 96354ea18f..073a1787d5 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -100,6 +100,7 @@ LLGLSLShader    gBenchmarkProgram;  LLGLSLShader    gReflectionProbeDisplayProgram;  LLGLSLShader    gCopyProgram;  LLGLSLShader    gCopyDepthProgram; +LLGLSLShader    gPBRTerrainBakeProgram;  //object shaders  LLGLSLShader        gObjectPreviewProgram; @@ -226,7 +227,7 @@ LLGLSLShader            gDeferredSkinnedPBROpaqueProgram;  LLGLSLShader            gHUDPBRAlphaProgram;  LLGLSLShader            gDeferredPBRAlphaProgram;  LLGLSLShader            gDeferredSkinnedPBRAlphaProgram; -LLGLSLShader            gDeferredPBRTerrainProgram; +LLGLSLShader            gDeferredPBRTerrainProgram[TERRAIN_PAINT_TYPE_COUNT];  LLGLSLShader            gGLTFPBRMetallicRoughnessProgram; @@ -432,7 +433,10 @@ void LLViewerShaderMgr::finalizeShaderList()      mShaderList.push_back(&gGLTFPBRMetallicRoughnessProgram);      mShaderList.push_back(&gDeferredAvatarProgram);      mShaderList.push_back(&gDeferredTerrainProgram); -    mShaderList.push_back(&gDeferredPBRTerrainProgram); +    for (U32 paint_type = 0; paint_type < TERRAIN_PAINT_TYPE_COUNT; ++paint_type) +    { +        mShaderList.push_back(&gDeferredPBRTerrainProgram[paint_type]); +    }      mShaderList.push_back(&gDeferredDiffuseAlphaMaskProgram);      mShaderList.push_back(&gDeferredNonIndexedDiffuseAlphaMaskProgram);      mShaderList.push_back(&gDeferredTreeProgram); @@ -1129,7 +1133,10 @@ bool LLViewerShaderMgr::loadShadersDeferred()          gDeferredSkinnedPBROpaqueProgram.unload();          gDeferredPBRAlphaProgram.unload();          gDeferredSkinnedPBRAlphaProgram.unload(); -        gDeferredPBRTerrainProgram.unload(); +        for (U32 paint_type = 0; paint_type < TERRAIN_PAINT_TYPE_COUNT; ++paint_type) +        { +            gDeferredPBRTerrainProgram[paint_type].unload(); +        }          return true;      } @@ -1443,25 +1450,31 @@ bool LLViewerShaderMgr::loadShadersDeferred()          S32 detail = gSavedSettings.getS32("RenderTerrainPBRDetail");          detail = llclamp(detail, TERRAIN_PBR_DETAIL_MIN, TERRAIN_PBR_DETAIL_MAX);          const S32 mapping = clamp_terrain_mapping(gSavedSettings.getS32("RenderTerrainPBRPlanarSampleCount")); -        gDeferredPBRTerrainProgram.mName = llformat("Deferred PBR Terrain Shader %d %s", -                detail, -                (mapping == 1 ? "flat" : "triplanar")); -        gDeferredPBRTerrainProgram.mFeatures.hasSrgb = true; -        gDeferredPBRTerrainProgram.mFeatures.isAlphaLighting = true; -        gDeferredPBRTerrainProgram.mFeatures.calculatesAtmospherics = true; -        gDeferredPBRTerrainProgram.mFeatures.hasAtmospherics = true; -        gDeferredPBRTerrainProgram.mFeatures.hasGamma = true; -        gDeferredPBRTerrainProgram.mFeatures.hasTransport = true; -        gDeferredPBRTerrainProgram.mFeatures.isPBRTerrain = true; +        for (U32 paint_type = 0; paint_type < TERRAIN_PAINT_TYPE_COUNT; ++paint_type) +        { +            LLGLSLShader* shader = &gDeferredPBRTerrainProgram[paint_type]; +            shader->mName = llformat("Deferred PBR Terrain Shader %d %s %s", +                    detail, +                    (paint_type == TERRAIN_PAINT_TYPE_PBR_PAINTMAP ? "paintmap" : "heightmap-with-noise"), +                    (mapping == 1 ? "flat" : "triplanar")); +            shader->mFeatures.hasSrgb = true; +            shader->mFeatures.isAlphaLighting = true; +            shader->mFeatures.calculatesAtmospherics = true; +            shader->mFeatures.hasAtmospherics = true; +            shader->mFeatures.hasGamma = true; +            shader->mFeatures.hasTransport = true; +            shader->mFeatures.isPBRTerrain = true; -        gDeferredPBRTerrainProgram.mShaderFiles.clear(); -        gDeferredPBRTerrainProgram.mShaderFiles.push_back(make_pair("deferred/pbrterrainV.glsl", GL_VERTEX_SHADER)); -        gDeferredPBRTerrainProgram.mShaderFiles.push_back(make_pair("deferred/pbrterrainF.glsl", GL_FRAGMENT_SHADER)); -        gDeferredPBRTerrainProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; -        gDeferredPBRTerrainProgram.addPermutation("TERRAIN_PBR_DETAIL", llformat("%d", detail)); -        gDeferredPBRTerrainProgram.addPermutation("TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT", llformat("%d", mapping)); -        success = gDeferredPBRTerrainProgram.createShader(); -        llassert(success); +            shader->mShaderFiles.clear(); +            shader->mShaderFiles.push_back(make_pair("deferred/pbrterrainV.glsl", GL_VERTEX_SHADER)); +            shader->mShaderFiles.push_back(make_pair("deferred/pbrterrainF.glsl", GL_FRAGMENT_SHADER)); +            shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; +            shader->addPermutation("TERRAIN_PBR_DETAIL", llformat("%d", detail)); +            shader->addPermutation("TERRAIN_PAINT_TYPE", llformat("%d", paint_type)); +            shader->addPermutation("TERRAIN_PLANAR_TEXTURE_SAMPLE_COUNT", llformat("%d", mapping)); +            success = success && shader->createShader(); +            llassert(success); +        }      }      if (success) @@ -2959,6 +2972,25 @@ bool LLViewerShaderMgr::loadShadersInterface()      if (success)      { +        LLGLSLShader* shader = &gPBRTerrainBakeProgram; +        U32 bit_depth = gSavedSettings.getU32("TerrainPaintBitDepth"); +        // LLTerrainPaintMap currently uses an RGB8 texture internally +        bit_depth = llclamp(bit_depth, 1, 8); +        shader->mName = llformat("Terrain Bake Shader RGB%o", bit_depth); +        shader->mFeatures.isPBRTerrain = true; + +        shader->mShaderFiles.clear(); +        shader->mShaderFiles.push_back(make_pair("interface/pbrTerrainBakeV.glsl", GL_VERTEX_SHADER)); +        shader->mShaderFiles.push_back(make_pair("interface/pbrTerrainBakeF.glsl", GL_FRAGMENT_SHADER)); +        shader->mShaderLevel = mShaderLevel[SHADER_INTERFACE]; +        const U32 value_range = (1 << bit_depth) - 1; +        shader->addPermutation("TERRAIN_PAINT_PRECISION", llformat("%d", value_range)); +        success = success && shader->createShader(); +        llassert(success); +    } + +    if (success) +    {          gAlphaMaskProgram.mName = "Alpha Mask Shader";          gAlphaMaskProgram.mShaderFiles.clear();          gAlphaMaskProgram.mShaderFiles.push_back(make_pair("interface/alphamaskV.glsl", GL_VERTEX_SHADER)); diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 60ce8c430b..af47014a43 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -174,6 +174,7 @@ extern LLGLSLShader         gBenchmarkProgram;  extern LLGLSLShader         gReflectionProbeDisplayProgram;  extern LLGLSLShader         gCopyProgram;  extern LLGLSLShader         gCopyDepthProgram; +extern LLGLSLShader         gPBRTerrainBakeProgram;  //output tex0[tc0] - tex1[tc1]  extern LLGLSLShader         gTwoTextureCompareProgram; @@ -304,5 +305,13 @@ enum TerrainPBRDetail : S32      TERRAIN_PBR_DETAIL_BASE_COLOR         = -4,      TERRAIN_PBR_DETAIL_MIN                = -4,  }; -extern LLGLSLShader         gDeferredPBRTerrainProgram; +enum TerrainPaintType : U32 +{ +    // Use LLVLComposition::mDatap (heightmap) generated by generateHeights, plus noise from TERRAIN_ALPHARAMP +    TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE = 0, +    // Use paint map if PBR terrain, otherwise fall back to TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE +    TERRAIN_PAINT_TYPE_PBR_PAINTMAP         = 1, +    TERRAIN_PAINT_TYPE_COUNT                = 2, +}; +extern LLGLSLShader         gDeferredPBRTerrainProgram[TERRAIN_PAINT_TYPE_COUNT];  #endif diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 9648a9af18..1369e3d306 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -42,6 +42,7 @@  #include "llstl.h"  #include "message.h"  #include "lltimer.h" +#include "v4coloru.h"  // viewer includes  #include "llimagegl.h" diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index f5f058a080..077e6e6cb1 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -312,6 +312,17 @@ bool LLTerrainMaterials::makeMaterialsReady(bool boost, bool strict)      return one_ready;  } +LLViewerTexture* LLTerrainMaterials::getPaintMap() +{ +    return mPaintMap.get(); +} + +void LLTerrainMaterials::setPaintMap(LLViewerTexture* paint_map) +{ +    llassert(!paint_map || mPaintType == TERRAIN_PAINT_TYPE_PBR_PAINTMAP); +    mPaintMap = paint_map; +} +  // Boost the texture loading priority  // Return true when ready to use (i.e. texture is sufficiently loaded)  // static diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index 2637d77183..f15f9bff6a 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -28,6 +28,8 @@  #define LL_LLVLCOMPOSITION_H  #include "llviewerlayer.h" +#include "llviewershadermgr.h" +#include "llviewertexture.h"  #include "llpointer.h"  #include "llimage.h" @@ -44,6 +46,7 @@ public:      virtual const LLGLTFMaterial* getMaterialOverride(S32 asset) const = 0;  }; +// The subset of the composition used by local terrain debug materials (gLocalTerrainMaterials)  class LLTerrainMaterials : public LLModifyRegion  {  public: @@ -79,6 +82,12 @@ public:      // strict = false -> at least one material must be loaded      bool makeMaterialsReady(bool boost, bool strict); +    // See TerrainPaintType +    U32 getPaintType() const { return mPaintType; } +    void setPaintType(U32 paint_type) { mPaintType = paint_type; } +    LLViewerTexture* getPaintMap(); +    void setPaintMap(LLViewerTexture* paint_map); +  protected:      void unboost();      static bool makeTextureReady(LLPointer<LLViewerFetchedTexture>& tex, bool boost); @@ -93,6 +102,9 @@ protected:      LLPointer<LLGLTFMaterial> mDetailMaterialOverrides[ASSET_COUNT];      LLPointer<LLFetchedGLTFMaterial> mDetailRenderMaterials[ASSET_COUNT];      bool mMaterialTexturesSet[ASSET_COUNT]; + +    U32 mPaintType = TERRAIN_PAINT_TYPE_HEIGHTMAP_WITH_NOISE; +    LLPointer<LLViewerTexture> mPaintMap;  };  // Local materials to override all regions diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 471174cf5d..b76717e660 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -245,7 +245,6 @@ bool LLVOSurfacePatch::updateLOD()  void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,                                                LLStrider<LLVector3> &normalsp, -                                              LLStrider<LLVector2> &texCoords0p,                                                LLStrider<LLVector2> &texCoords1p,                                                LLStrider<U16> &indicesp)  { @@ -260,21 +259,18 @@ void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,      updateMainGeometry(facep,                      verticesp,                      normalsp, -                    texCoords0p,                      texCoords1p,                      indicesp,                      index_offset);      updateNorthGeometry(facep,                          verticesp,                          normalsp, -                        texCoords0p,                          texCoords1p,                          indicesp,                          index_offset);      updateEastGeometry(facep,                          verticesp,                          normalsp, -                        texCoords0p,                          texCoords1p,                          indicesp,                          index_offset); @@ -283,7 +279,6 @@ void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,  void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,                                          LLStrider<LLVector3> &verticesp,                                          LLStrider<LLVector3> &normalsp, -                                        LLStrider<LLVector2> &texCoords0p,                                          LLStrider<LLVector2> &texCoords1p,                                          LLStrider<U16> &indicesp,                                          U32 &index_offset) @@ -322,10 +317,9 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,              {                  x = i * render_stride;                  y = j * render_stride; -                mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +                mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());                  verticesp++;                  normalsp++; -                texCoords0p++;                  texCoords1p++;              }          } @@ -387,7 +381,6 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,  void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,                                          LLStrider<LLVector3> &verticesp,                                          LLStrider<LLVector3> &normalsp, -                                        LLStrider<LLVector2> &texCoords0p,                                          LLStrider<LLVector2> &texCoords1p,                                          LLStrider<U16> &indicesp,                                          U32 &index_offset) @@ -421,10 +414,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * render_stride;              y = 16 - render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -433,10 +425,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,          {              x = i * render_stride;              y = 16; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -469,10 +460,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * render_stride;              y = 16 - render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -482,10 +472,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * render_stride;              y = 16; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -525,10 +514,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * north_stride;              y = 16 - render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -538,10 +526,9 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * north_stride;              y = 16; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -577,7 +564,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,                                            LLStrider<LLVector3> &verticesp,                                            LLStrider<LLVector3> &normalsp, -                                          LLStrider<LLVector2> &texCoords0p,                                            LLStrider<LLVector2> &texCoords1p,                                            LLStrider<U16> &indicesp,                                            U32 &index_offset) @@ -606,10 +592,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16 - render_stride;              y = i * render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -618,10 +603,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,          {              x = 16;              y = i * render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -654,10 +638,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16 - render_stride;              y = i * render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          }          // Iterate through the east patch's points @@ -666,10 +649,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16;              y = i * render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -708,10 +690,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16 - render_stride;              y = i * east_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          }          // Iterate through the east patch's points @@ -720,10 +701,9 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16;              y = i * east_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get());              verticesp++;              normalsp++; -            texCoords0p++;              texCoords1p++;          } @@ -992,8 +972,8 @@ void gen_terrain_tangents(U16                    strider_vertex_count,                            LLStrider<LLVector3>  &verticesp,                            LLStrider<LLVector3>  &normalsp,                            LLStrider<LLVector4a> &tangentsp, -                          LLStrider<LLVector2>  &texCoords0p, -                          LLStrider<U16>        &indicesp) +                          LLStrider<U16>        &indicesp, +                          F32 region_width)  {      LL_PROFILE_ZONE_SCOPED; @@ -1010,7 +990,10 @@ void gen_terrain_tangents(U16                    strider_vertex_count,          F32 *n       = normalsp[v].mV;          normals[v]   = LLVector4a(n[0], n[1], n[2], 1.f);          tangents[v]  = tangentsp[v]; -        texcoords[v] = texCoords0p[v]; + +        // Calculate texcoords on-the-fly using the terrain positions +        texcoords[v].mV[VX] = verticesp[v].mV[VX] / region_width; +        texcoords[v].mV[VY] = verticesp[v].mV[VY] / region_width;      }      for (U32 i = 0; i < strider_index_count; ++i)      { @@ -1039,14 +1022,12 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)      LLStrider<LLVector3> vertices_start;      LLStrider<LLVector3> normals_start;      LLStrider<LLVector4a> tangents_start; -    LLStrider<LLVector2> texcoords_start;      LLStrider<LLVector2> texcoords2_start;      LLStrider<U16> indices_start;      llassert_always(buffer->getVertexStrider(vertices_start));      llassert_always(buffer->getNormalStrider(normals_start));      llassert_always(buffer->getTangentStrider(tangents_start)); -    llassert_always(buffer->getTexCoord0Strider(texcoords_start));      llassert_always(buffer->getTexCoord1Strider(texcoords2_start));      llassert_always(buffer->getIndexStrider(indices_start)); @@ -1056,7 +1037,6 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)      {          LLStrider<LLVector3> vertices = vertices_start;          LLStrider<LLVector3> normals = normals_start; -        LLStrider<LLVector2> texcoords = texcoords_start;          LLStrider<LLVector2> texcoords2 = texcoords2_start;          LLStrider<U16> indices = indices_start; @@ -1069,7 +1049,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)              facep->setVertexBuffer(buffer);              LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject(); -            patchp->getTerrainGeometry(vertices, normals, texcoords, texcoords2, indices); +            patchp->getTerrainGeometry(vertices, normals, texcoords2, indices);              indices_index += facep->getIndicesCount();              index_offset += facep->getGeomCount(); @@ -1082,10 +1062,20 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)          LLStrider<LLVector3> vertices = vertices_start;          LLStrider<LLVector3> normals = normals_start;          LLStrider<LLVector4a> tangents = tangents_start; -        LLStrider<LLVector2> texcoords = texcoords_start;          LLStrider<U16> indices = indices_start; -        gen_terrain_tangents(index_offset, indices_index, vertices, normals, tangents, texcoords, indices); +        F32 region_width = 256.0f; +        if (mFaceList.empty()) +        { +            llassert(false); +        } +        else +        { +            const LLViewerRegion* regionp = mFaceList[0]->getViewerObject()->getRegion(); +            llassert(regionp == mFaceList.back()->getViewerObject()->getRegion()); // Assume this spatial group is confined to one region +            region_width = regionp->getWidth(); +        } +        gen_terrain_tangents(index_offset, indices_index, vertices, normals, tangents, indices, region_width);      }      buffer->unmapBuffer(); diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h index 2780b97a97..af5f05774b 100644 --- a/indra/newview/llvosurfacepatch.h +++ b/indra/newview/llvosurfacepatch.h @@ -41,14 +41,6 @@ class LLVOSurfacePatch : public LLStaticViewerObject  public:      static F32 sLODFactor; -    enum -    { -        VERTEX_DATA_MASK =  (1 << LLVertexBuffer::TYPE_VERTEX) | -                            (1 << LLVertexBuffer::TYPE_NORMAL) | -                            (1 << LLVertexBuffer::TYPE_TEXCOORD0) | -                            (1 << LLVertexBuffer::TYPE_TEXCOORD1) -    }; -      LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);      /*virtual*/ void markDead(); @@ -65,7 +57,6 @@ public:      /*virtual*/ void        updateFaceSize(S32 idx);      void getTerrainGeometry(LLStrider<LLVector3> &verticesp,                                  LLStrider<LLVector3> &normalsp, -                                LLStrider<LLVector2> &texCoords0p,                                  LLStrider<LLVector2> &texCoords1p,                                  LLStrider<U16> &indicesp); @@ -118,21 +109,18 @@ protected:      void updateMainGeometry(LLFace *facep,                         LLStrider<LLVector3> &verticesp,                         LLStrider<LLVector3> &normalsp, -                       LLStrider<LLVector2> &texCoords0p,                         LLStrider<LLVector2> &texCoords1p,                         LLStrider<U16> &indicesp,                         U32 &index_offset);      void updateNorthGeometry(LLFace *facep,                         LLStrider<LLVector3> &verticesp,                         LLStrider<LLVector3> &normalsp, -                       LLStrider<LLVector2> &texCoords0p,                         LLStrider<LLVector2> &texCoords1p,                         LLStrider<U16> &indicesp,                         U32 &index_offset);      void updateEastGeometry(LLFace *facep,                         LLStrider<LLVector3> &verticesp,                         LLStrider<LLVector3> &normalsp, -                       LLStrider<LLVector2> &texCoords0p,                         LLStrider<LLVector2> &texCoords1p,                         LLStrider<U16> &indicesp,                         U32 &index_offset); diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 941f0c6bb7..98cf03b30e 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3435,13 +3435,6 @@ function="World.EnvPreset"              <menu_item_call.on_click               function="Advanced.ClearShaderCache" />            </menu_item_call> -          <menu_item_call -            enabled="true" -            label="Rebuild Terrain" -            name="Rebuild Terrain"> -            <menu_item_call.on_click -             function="Advanced.RebuildTerrain" /> -          </menu_item_call>            <menu_item_separator />            <menu_item_call              enabled="true" @@ -3662,6 +3655,37 @@ function="World.EnvPreset"                   function="Advanced.ResetInterestLists" />  			</menu_item_call>  		</menu> +        <!-- terrain --> +        <menu +         create_jump_keys="true" +         label="Terrain" +         name="DevelopTerrain" +         tear_off="true"> +            <menu_item_call +              enabled="true" +              label="Rebuild Terrain" +              name="Rebuild Terrain"> +              <menu_item_call.on_click +               function="Advanced.RebuildTerrain" /> +            </menu_item_call> + +            <menu_item_separator/> + +            <menu_item_call +              enabled="true" +              label="Create Local Paintmap" +              name="Create Local Paintmap"> +              <menu_item_call.on_click +               function="Advanced.TerrainCreateLocalPaintMap" /> +            </menu_item_call> +            <menu_item_call +              enabled="true" +              label="Delete Local Paintmap" +              name="Delete Local Paintmap"> +              <menu_item_call.on_click +               function="Advanced.TerrainDeleteLocalPaintMap" /> +            </menu_item_call> +		</menu>          <menu           create_jump_keys="true"           label="UI" | 
