diff options
Diffstat (limited to 'indra/newview')
299 files changed, 17183 insertions, 5635 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f13ce85495..213b34b4a6 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -56,7 +56,8 @@ include(UnixInstall) include(ViewerMiscLibs) include(ViewerManager) include(VisualLeakDetector) -include(ZLIB) +include(VulkanGltf) +include(ZLIBNG) include(URIPARSER) if (NOT HAVOK_TPV) @@ -187,6 +188,7 @@ set(viewer_SOURCE_FILES lldrawpoolbump.cpp lldrawpoolground.cpp lldrawpoolmaterials.cpp + lldrawpoolpbropaque.cpp lldrawpoolsimple.cpp lldrawpoolsky.cpp lldrawpoolterrain.cpp @@ -341,6 +343,7 @@ set(viewer_SOURCE_FILES llgesturemgr.cpp llgiveinventory.cpp llglsandbox.cpp + llgltfmateriallist.cpp llgroupactions.cpp llgroupiconctrl.cpp llgrouplist.cpp @@ -390,6 +393,7 @@ set(viewer_SOURCE_FILES lllistcontextmenu.cpp lllistview.cpp lllocalbitmaps.cpp + lllocalgltfmaterials.cpp lllocationhistory.cpp lllocationinputctrl.cpp lllogchat.cpp @@ -402,6 +406,7 @@ set(viewer_SOURCE_FILES llmaniptranslate.cpp llmarketplacefunctions.cpp llmarketplacenotifications.cpp + llmaterialeditor.cpp llmaterialmgr.cpp llmediactrl.cpp llmediadataclient.cpp @@ -544,6 +549,8 @@ set(viewer_SOURCE_FILES llproductinforequest.cpp llprogressview.cpp llrecentpeople.cpp + llreflectionmap.cpp + llreflectionmapmanager.cpp llregioninfomodel.cpp llregionposition.cpp llremoteparcelrequest.cpp @@ -600,6 +607,7 @@ set(viewer_SOURCE_FILES lltextureinfodetails.cpp lltexturestats.cpp lltextureview.cpp + lltinygltfhelper.cpp lltoast.cpp lltoastalertpanel.cpp lltoastgroupnotifypanel.cpp @@ -821,6 +829,7 @@ set(viewer_HEADER_FILES lldrawpoolavatar.h lldrawpoolbump.h lldrawpoolmaterials.h + lldrawpoolpbropaque.h lldrawpoolground.h lldrawpoolsimple.h lldrawpoolsky.h @@ -978,6 +987,7 @@ set(viewer_HEADER_FILES llgesturelistener.h llgesturemgr.h llgiveinventory.h + llgltfmateriallist.h llgroupactions.h llgroupiconctrl.h llgrouplist.h @@ -1026,6 +1036,7 @@ set(viewer_HEADER_FILES lllistcontextmenu.h lllistview.h lllocalbitmaps.h + lllocalgltfmaterials.h lllocationhistory.h lllocationinputctrl.h lllogchat.h @@ -1038,6 +1049,7 @@ set(viewer_HEADER_FILES llmaniptranslate.h llmarketplacefunctions.h llmarketplacenotifications.h + llmaterialeditor.h llmaterialmgr.h llmediactrl.h llmediadataclient.h @@ -1167,6 +1179,8 @@ set(viewer_HEADER_FILES llproductinforequest.h llprogressview.h llrecentpeople.h + llreflectionmap.h + llreflectionmapmanager.h llregioninfomodel.h llregionposition.h llremoteparcelrequest.h @@ -1227,6 +1241,7 @@ set(viewer_HEADER_FILES lltextureinfodetails.h lltexturestats.h lltextureview.h + lltinygltfhelper.h lltoast.h lltoastalertpanel.h lltoastgroupnotifypanel.h @@ -1841,10 +1856,6 @@ if (WINDOWS) winmm_shim ) - if (NOT USE_BUGSPLAT) - LIST(APPEND COPY_INPUT_DEPENDENCIES windows-crash-logger) - endif (NOT USE_BUGSPLAT) - if (ADDRESS_SIZE EQUAL 64) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk_x64.dll @@ -2009,14 +2020,14 @@ endif (WINDOWS) # # We generally want the newest version of the library to provide all symbol # resolution. To that end, when using static archives, the *_PRELOAD_ARCHIVES -# variables, PNG_PRELOAD_ARCHIVES and ZLIB_PRELOAD_ARCHIVES, get the archives +# variables, PNG_PRELOAD_ARCHIVES and ZLIBNG_PRELOAD_ARCHIVES, get the archives # dumped into the target binary and runtime lookup will find the most # modern version. target_link_libraries(${VIEWER_BINARY_NAME} ${LEGACY_STDIO_LIBS} ${PNG_PRELOAD_ARCHIVES} - ${ZLIB_PRELOAD_ARCHIVES} + ${ZLIBNG_PRELOAD_ARCHIVES} ${URIPARSER_PRELOAD_ARCHIVES} ${GOOGLE_PERFTOOLS_LIBRARIES} ${LLAUDIO_LIBRARIES} diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 09a7391e4e..66ce77b7ea 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.6.1 +7.0.0 diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index dd2b656ce3..e16a5c7e76 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -55,7 +55,7 @@ <key>debugsession</key> <map> <key>desc</key> - <string>Run as if RenderDebugGL is TRUE, but log errors until end of session.</string> + <string>Run as if RenderDebugGLSession is TRUE, but log errors until end of session.</string> <key>map-to</key> <string>DebugSession</string> </map> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index afa8217af2..cd33690075 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1252,6 +1252,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>BulkChangeIncludeMaterials</key> + <map> + <key>Comment</key> + <string>Bulk permission changes affect materials</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>BulkChangeEveryoneCopy</key> <map> <key>Comment</key> @@ -3870,7 +3881,7 @@ <key>Type</key> <string>String</string> <key>Value</key> - <string>http://events.secondlife.com/viewer/embed/event/</string> + <string>http://events.[GRID]/viewer/embed/event/[EVENT_ID]</string> </map> <key>FastCacheFetchEnabled</key> <map> @@ -8658,6 +8669,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>UpdateRememberPasswordSetting</key> + <map> + <key>Comment</key> + <string>Save 'rememeber password' setting for current user.</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>OctreeMaxNodeCapacity</key> <map> <key>Comment</key> @@ -8807,13 +8829,13 @@ <key>RenderAvatarCloth</key> <map> <key>Comment</key> - <string>Controls if avatars use wavy cloth</string> + <string>DEPRECATED - only false supported - Controls if avatars use wavy cloth</string> <key>Persist</key> <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>1</integer> + <integer>0</integer> </map> <key>RenderComplexityColorMin</key> <map> @@ -9164,10 +9186,10 @@ <key>Value</key> <real>0.5</real> </map> - <key>RenderDebugGL</key> + <key>RenderDebugGLSession</key> <map> <key>Comment</key> - <string>Enable strict GL debugging.</string> + <string>Enable strict GL debugging on the start of next session.</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -9622,16 +9644,28 @@ <real>368.0</real> </map> + <key>RenderPBR</key> + <map> + <key>Comment</key> + <string>Use PBR rendering pipeline (Physically Based Rendering).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>RenderDeferred</key> <map> <key>Comment</key> - <string>Use deferred rendering pipeline (Advanced Lighting Model).</string> + <string>DEPRECATED (only true supported) - Use deferred rendering pipeline (Advanced Lighting Model).</string> <key>Persist</key> <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>0</integer> + <integer>1</integer> </map> <key>RenderDeferredSun</key> @@ -9846,7 +9880,7 @@ <key>RenderFogRatio</key> <map> <key>Comment</key> - <string>Distance from camera where fog reaches maximum density (fraction or multiple of far clip distance)</string> + <string>DEPRECATED - Distance from camera where fog reaches maximum density (fraction or multiple of far clip distance)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -9857,7 +9891,7 @@ <key>RenderGamma</key> <map> <key>Comment</key> - <string>Sets gamma exponent for renderer</string> + <string>DEPRECATED - Sets gamma exponent for renderer</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -10250,7 +10284,7 @@ <key>RenderObjectBump</key> <map> <key>Comment</key> - <string>Show bumpmapping on primitives</string> + <string>DEPRECATED (only TRUE supported) Show bumpmapping on primitives</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -10291,8 +10325,64 @@ <key>Value</key> <integer>2</integer> </map> + <key>RenderReflectionProbeDetail</key> + <map> + <key>Comment</key> + <string>Detail of reflections.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>RenderReflectionProbeCount</key> + <map> + <key>Comment</key> + <string>Number of reflection probes (maximum is 256, requires restart)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>256</integer> + </map> - <key>RenderReflectionRes</key> + <key>RenderReflectionProbeDrawDistance</key> + <map> + <key>Comment</key> + <string>Camera far clip to use when updating reflection probes.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>64</real> + </map> + <key>RenderReflectionProbeAmbiance</key> + <map> + <key>Comment</key> + <string>Amount reflection probes contribute to ambient light.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0</real> + </map> + <key>RenderReflectionProbeTextureHackID</key> + <map> + <key>Comment</key> + <string>HACK -- Any object with a diffuse texture with this ID will be treated as a user override reflection probe. (default is "Violet Info Hub" photo from Library)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>6b186931-05da-eafa-a3ed-a012a33bbfb6</string> + </map> + + <key>RenderReflectionRes</key> <map> <key>Comment</key> <string>Reflection map resolution.</string> @@ -11157,6 +11247,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>SelectInvisibleObjects</key> + <map> + <key>Comment</key> + <string>Select invisible objects</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>SelectOwnedOnly</key> <map> <key>Comment</key> @@ -14758,7 +14859,7 @@ <key>WindLightUseAtmosShaders</key> <map> <key>Comment</key> - <string>Whether to enable or disable WindLight atmospheric shaders.</string> + <string>DEPRECATED (only true supported) - Whether to enable or disable WindLight atmospheric shaders.</string> <key>Persist</key> <integer>1</integer> <key>Type</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl index 23adbded5e..73c125bbdc 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl @@ -29,8 +29,6 @@ uniform sampler2DRect depthMap; uniform float ssao_radius; uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv; uniform mat4 inv_proj; uniform vec2 screen_res; @@ -83,14 +81,14 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen) { float ret = 1.0; vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy; + float angle_hidden = 0.0; float points = 0; - float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) + float scale = min(ssao_radius / -pos_world.z, ssao_max_radius); + vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy; for (int i = 0; i < 8; i++) { vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect); @@ -105,14 +103,14 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen) //(k should vary inversely with # of samples, but this is taken care of later) float funky_val = (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) ? 1.0 : 0.0; - angle_hidden = angle_hidden + funky_val * min(1.0/dist2, ssao_factor_inv); + angle_hidden = angle_hidden + funky_val * min(1.0/dist2, 1.0); // 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" float diffz_val = (diff.z > -1.0) ? 1.0 : 0.0; points = points + diffz_val; } - - angle_hidden = min(ssao_factor*angle_hidden/points, 1.0); + + angle_hidden = min(angle_hidden/points, 1.0); float points_val = (points > 0.0) ? 1.0 : 0.0; ret = (1.0 - (points_val * angle_hidden)); diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl index 60d83cc623..22b3bd1463 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl @@ -52,6 +52,6 @@ void main() frag_data[0] = vec4(diff.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 596d0274af..fa3634f3b6 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -69,36 +69,47 @@ void main() tc_mod *= 2.0; tc += ( (tc_mod - 0.5) * kern[1].z * dlt * 0.5 ); - for (int i = 1; i < 4; i++) + // TODO: move this to kern instead of building kernel per pixel + vec3 k[7]; + k[0] = kern[0]; + k[2] = kern[1]; + k[4] = kern[2]; + k[6] = kern[3]; + + k[1] = (k[0]+k[2])*0.5f; + k[3] = (k[2]+k[4])*0.5f; + k[5] = (k[4]+k[6])*0.5f; + + for (int i = 1; i < 7; i++) { - vec2 samptc = tc + kern[i].z*dlt; + vec2 samptc = tc + k[i].z*dlt*2.0; vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2DRect(lightMap, samptc)*kern[i].xyxx; - defined_weight += kern[i].xy; + col += texture2DRect(lightMap, samptc)*k[i].xyxx; + defined_weight += k[i].xy; } } - for (int i = 1; i < 4; i++) + for (int i = 1; i < 7; i++) { - vec2 samptc = tc - kern[i].z*dlt; + vec2 samptc = tc - k[i].z*dlt*2.0; vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2DRect(lightMap, samptc)*kern[i].xyxx; - defined_weight += kern[i].xy; + col += texture2DRect(lightMap, samptc)*k[i].xyxx; + defined_weight += k[i].xy; } } col /= defined_weight.xyxx; - col.y *= col.y; + //col.y *= max(col.y, 0.75); frag_color = col; diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl index b5677a07ee..749ec3a6ac 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl @@ -64,5 +64,5 @@ void main() frag_data[1] = vertex_color.aaaa; // spec //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested vec3 nvn = normalize(tnorm); - frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, 0.0); + frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl index ae1ac5de7f..348e0f5228 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl @@ -124,7 +124,7 @@ void main() /// Gamma correct for WL (soft clip effect). frag_data[0] = vec4(color.rgb, alpha1); frag_data[1] = vec4(0.0,0.0,0.0,0.0); - frag_data[2] = vec4(0,0,0,1); + frag_data[2] = vec4(0,0,0,GBUFFER_FLAG_SKIP_ATMOS); gl_FragDepth = 0.99995f; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl index e27bbce094..68a57d12f0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl @@ -25,10 +25,88 @@ uniform sampler2DRect normalMap; uniform sampler2DRect depthMap; +uniform sampler2D projectionMap; // rgba + +// projected lighted params +uniform mat4 proj_mat; //screen space to light space projector +uniform vec3 proj_n; // projector normal +uniform vec3 proj_p; //plane projection is emitting from (in screen space) +uniform float proj_focus; // distance from plane to begin blurring +uniform float proj_lod ; // (number of mips in proj map) +uniform float proj_range; // range between near clip and far clip plane of projection +uniform float proj_ambiance; + +// light params +uniform vec3 color; // light_color +uniform float size; // light_size uniform mat4 inv_proj; uniform vec2 screen_res; +const float M_PI = 3.14159265; +const float ONE_OVER_PI = 0.3183098861; + +vec3 srgb_to_linear(vec3 cs); + +float calcLegacyDistanceAttenuation(float distance, float falloff) +{ + float dist_atten = 1.0 - clamp((distance + falloff)/(1.0 + falloff), 0.0, 1.0); + dist_atten *= dist_atten; + + // Tweak falloff slightly to match pre-EEP attenuation + // NOTE: this magic number also shows up in a great many other places, search for dist_atten *= to audit + dist_atten *= 2.0; + return dist_atten; +} + +// In: +// lv unnormalized surface to light vector +// n normal of the surface +// pos unnormalized camera to surface vector +// Out: +// l normalized surace to light vector +// nl diffuse angle +// nh specular angle +void calcHalfVectors(vec3 lv, vec3 n, vec3 v, + out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist) +{ + l = normalize(lv); + h = normalize(l + v); + nh = clamp(dot(n, h), 0.0, 1.0); + nl = clamp(dot(n, l), 0.0, 1.0); + nv = clamp(dot(n, v), 0.0, 1.0); + vh = clamp(dot(v, h), 0.0, 1.0); + + lightDist = length(lv); +} + +// In: +// light_center +// pos +// Out: +// dist +// l_dist +// lv +// proj_tc Projector Textue Coordinates +bool clipProjectedLightVars(vec3 light_center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc ) +{ + lv = light_center - pos.xyz; + dist = length(lv); + bool clipped = (dist >= size); + if ( !clipped ) + { + dist /= size; + + l_dist = -dot(lv, proj_n); + vec4 projected_point = (proj_mat * vec4(pos.xyz, 1.0)); + clipped = (projected_point.z < 0.0); + projected_point.xyz /= projected_point.w; + proj_tc = projected_point; + } + + return clipped; +} + vec2 getScreenCoordinate(vec2 screenpos) { vec2 sc = screenpos.xy * 2.0; @@ -39,6 +117,8 @@ vec2 getScreenCoordinate(vec2 screenpos) return sc - vec2(1.0, 1.0); } +// See: https://aras-p.info/texts/CompactNormalStorage.html +// Method #4: Spheremap Transform, Lambert Azimuthal Equal-Area projection vec3 getNorm(vec2 screenpos) { vec2 enc = texture2DRect(normalMap, screenpos.xy).xy; @@ -51,12 +131,136 @@ vec3 getNorm(vec2 screenpos) return n; } +vec3 getNormalFromPacked(vec4 packedNormalEnvIntensityFlags) +{ + vec2 enc = packedNormalEnvIntensityFlags.xy; + vec2 fenc = enc*4-2; + float f = dot(fenc,fenc); + float g = sqrt(1-f/4); + vec3 n; + n.xy = fenc*g; + n.z = 1-f/2; + return normalize(n); // TODO: Is this normalize redundant? +} + +// return packedNormalEnvIntensityFlags since GBUFFER_FLAG_HAS_PBR needs .w +// See: C++: addDeferredAttachments(), GLSL: softenLightF +vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity) +{ + vec4 packedNormalEnvIntensityFlags = texture2DRect(normalMap, screenpos.xy); + n = getNormalFromPacked( packedNormalEnvIntensityFlags ); + envIntensity = packedNormalEnvIntensityFlags.z; + return packedNormalEnvIntensityFlags; +} + float getDepth(vec2 pos_screen) { float depth = texture2DRect(depthMap, pos_screen).r; return depth; } +vec4 getTexture2DLodAmbient(vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + ret.rgb = srgb_to_linear(ret.rgb); + + vec2 dist = tc-vec2(0.5); + float d = dot(dist,dist); + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + +vec4 getTexture2DLodDiffuse(vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + ret.rgb = srgb_to_linear(ret.rgb); + + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + float det = min(lod/(proj_lod*0.5), 1.0); + float d = min(dist.x, dist.y); + float edge = 0.25*det; + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +// lit This is set by the caller: if (nl > 0.0) { lit = attenuation * nl * noise; } +// Uses: +// color Projected spotlight color +vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv) +{ + vec4 amb_plcol = getTexture2DLodAmbient(projected_uv, proj_lod); + vec3 amb_rgb = amb_plcol.rgb * amb_plcol.a; + + amb_da += proj_ambiance; + amb_da += (nl*nl*0.5+0.5) * proj_ambiance; + amb_da *= attenuation * noise; + amb_da = min(amb_da, 1.0-lit); + + return (amb_da * color.rgb * amb_rgb); +} + +// Returns projected light in Linear +// Uses global spotlight color: +// color +// NOTE: projected.a will be pre-multiplied with projected.rgb +vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv) +{ + float diff = clamp((light_distance - proj_focus)/proj_range, 0.0, 1.0); + float lod = diff * proj_lod; + vec4 plcol = getTexture2DLodDiffuse(projected_uv.xy, lod); + + return color.rgb * plcol.rgb * plcol.a; +} + +vec4 texture2DLodSpecular(vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + ret.rgb = srgb_to_linear(ret.rgb); + + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + float det = min(lod/(proj_lod*0.5), 1.0); + float d = min(dist.x, dist.y); + d *= min(1, d * (proj_lod - lod)); // BUG? extra factor compared to diffuse causes N repeats + float edge = 0.25*det; + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +// See: clipProjectedLightVars() +vec3 getProjectedLightSpecularColor(vec3 pos, vec3 n ) +{ + vec3 slit = vec3(0); + vec3 ref = reflect(normalize(pos), n); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float l_dist = length(pdelta); + float ds = dot(ref, proj_n); + if (ds < 0.0) + { + vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); + if (stc.z > 0.0) + { + stc /= stc.w; + slit = getProjectedLightDiffuseColor( l_dist, stc.xy ); // NOTE: Using diffuse due to texture2DLodSpecular() has extra: d *= min(1, d * (proj_lod - lod)); + } + } + return slit; // specular light +} + +vec3 getProjectedLightSpecularColor(float light_distance, vec2 projected_uv) +{ + float diff = clamp((light_distance - proj_focus)/proj_range, 0.0, 1.0); + float lod = diff * proj_lod; + vec4 plcol = getTexture2DLodDiffuse(projected_uv.xy, lod); // NOTE: Using diffuse due to texture2DLodSpecular() has extra: d *= min(1, d * (proj_lod - lod)); + + return color.rgb * plcol.rgb * plcol.a; +} + vec4 getPosition(vec2 pos_screen) { float depth = getDepth(pos_screen); @@ -77,3 +281,191 @@ vec4 getPositionWithDepth(vec2 pos_screen, float depth) pos.w = 1.0; return pos; } + +vec2 getScreenXY(vec4 clip) +{ + vec4 ndc = clip; + ndc.xyz /= clip.w; + vec2 screen = vec2( ndc.xy * 0.5 ); + screen += 0.5; + screen *= screen_res; + return screen; +} + +// Color utils + +vec3 colorize_dot(float x) +{ + if (x > 0.0) return vec3( 0, x, 0 ); + if (x < 0.0) return vec3(-x, 0, 0 ); + return vec3( 0, 0, 1 ); +} + +vec3 hue_to_rgb(float hue) +{ + if (hue > 1.0) return vec3(0.5); + vec3 rgb = abs(hue * 6. - vec3(3, 2, 4)) * vec3(1, -1, -1) + vec3(-1, 2, 2); + return clamp(rgb, 0.0, 1.0); +} + +// PBR Utils + +// ior Index of Refraction, normally 1.5 +// returns reflect0 +float calcF0(float ior) +{ + float f0 = (1.0 - ior) / (1.0 + ior); + return f0 * f0; +} + +vec3 fresnel(float vh, vec3 f0, vec3 f90 ) +{ + float x = 1.0 - abs(vh); + float x2 = x*x; + float x5 = x2*x2*x; + vec3 fr = f0 + (f90 - f0)*x5; + return fr; +} + +vec3 fresnelSchlick( vec3 reflect0, vec3 reflect90, float vh) +{ + return reflect0 + (reflect90 - reflect0) * pow(clamp(1.0 - vh, 0.0, 1.0), 5.0); +} + +// Approximate Environment BRDF +vec2 getGGXApprox( vec2 uv ) +{ + // Reference: Physically Based Shading on Mobile + // https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile + // EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV ) + float nv = uv.x; + float roughness = uv.y; + + const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022 ); + const vec4 c1 = vec4( 1, 0.0425, 1.04 , -0.04 ); + vec4 r = roughness * c0 + c1; + float a004 = min( r.x * r.x, exp2( -9.28 * nv ) ) * r.x + r.y; + vec2 ScaleBias = vec2( -1.04, 1.04 ) * a004 + r.zw; + return ScaleBias; +} + +#define PBR_USE_GGX_APPROX 1 +vec2 getGGX( vec2 brdfPoint ) +{ +#if PBR_USE_GGX_APPROX + return getGGXApprox( brdfPoint); +#else + return texture2D(GGXLUT, brdfPoint).rg; // TODO: use GGXLUT +#endif +} + + +// Reference: float getRangeAttenuation(float range, float distance) +float getLightAttenuationPointSpot(float range, float distance) +{ +#if 1 + return distance; +#else + float range2 = pow(range, 2.0); + + // support negative range as unlimited + if (range <= 0.0) + { + return 1.0 / range2; + } + + return max(min(1.0 - pow(distance / range, 4.0), 1.0), 0.0) / range2; +#endif +} + +vec3 getLightIntensityPoint(vec3 lightColor, float lightRange, float lightDistance) +{ + float rangeAttenuation = getLightAttenuationPointSpot(lightRange, lightDistance); + return rangeAttenuation * lightColor; +} + +float getLightAttenuationSpot(vec3 spotDirection) +{ + return 1.0; +} + +vec3 getLightIntensitySpot(vec3 lightColor, float lightRange, float lightDistance, vec3 v) +{ + float spotAttenuation = getLightAttenuationSpot(-v); + return spotAttenuation * getLightIntensityPoint( lightColor, lightRange, lightDistance ); +} + +// NOTE: This is different from the GGX texture +float D_GGX( float nh, float alphaRough ) +{ + float rough2 = alphaRough * alphaRough; + float f = (nh * nh) * (rough2 - 1.0) + 1.0; + return rough2 / (M_PI * f * f); +} + +// NOTE: This is different from the GGX texture +// See: +// Real Time Rendering, 4th Edition +// Page 341 +// Equation 9.43 +// Also see: +// https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg) +// 4.4.2 Geometric Shadowing (specular G) +float V_GGX( float nl, float nv, float alphaRough ) +{ +#if 1 + // Note: When roughness is zero, has discontuinity in the bottom hemisphere + float rough2 = alphaRough * alphaRough; + float ggxv = nl * sqrt(nv * nv * (1.0 - rough2) + rough2); + float ggxl = nv * sqrt(nl * nl * (1.0 - rough2) + rough2); + + float ggx = ggxv + ggxl; + if (ggx > 0.0) + { + return 0.5 / ggx; + } + return 0.0; +#else + // See: smithVisibility_GGXCorrelated, V_SmithCorrelated, etc. + float rough2 = alphaRough * alphaRough; + float ggxv = nl * sqrt(nv * (nv - rough2 * nv) + rough2); + float ggxl = nv * sqrt(nl * (nl - rough2 * nl) + rough2); + return 0.5 / (ggxv + ggxl); +#endif + +} + +// NOTE: Assumes a hard-coded IOR = 1.5 +void initMaterial( vec3 diffuse, vec3 packedORM, out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight ) +{ + float metal = packedORM.b; + c_diff = mix(diffuse, vec3(0), metal); + float IOR = 1.5; // default Index Of Refraction 1.5 (dielectrics) + reflect0 = vec3(0.04); // -> incidence reflectance 0.04 +// reflect0 = vec3(calcF0(IOR)); + reflect0 = mix(reflect0, diffuse, metal); // reflect at 0 degrees + reflect90 = vec3(1); // reflect at 90 degrees + specWeight = 1.0; + + // When roughness is zero blender shows a tiny specular + float perceptualRough = max(packedORM.g, 0.1); + alphaRough = perceptualRough * perceptualRough; +} + +vec3 BRDFDiffuse(vec3 color) +{ + return color * ONE_OVER_PI; +} + +vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh ) +{ + return (1.0 - specWeight * fresnelSchlick( reflect0, reflect90, vh)) * BRDFDiffuse(c_diff); +} + +vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRough, float specWeight, float vh, float nl, float nv, float nh ) +{ + vec3 fresnel = fresnelSchlick( reflect0, reflect90, vh ); // Fresnel + float vis = V_GGX( nl, nv, alphaRough ); // Visibility + float d = D_GGX( nh, alphaRough ); // Distribution + return specWeight * fresnel * vis * d; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl index b328ee9483..3bf148502c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl @@ -53,6 +53,6 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl index fc5c86b4d6..e15239b59d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl @@ -52,5 +52,5 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl index 1bb8eb8bd0..b0ff233414 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl @@ -52,6 +52,6 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl index 8319e61242..b2d2e2fa71 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl @@ -46,6 +46,6 @@ void main() frag_data[1] = vertex_color.aaaa; // spec //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl index ccd1df84f9..b4bc114dd5 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl @@ -48,5 +48,5 @@ void main() frag_data[0] = vec4(col, 0.0); frag_data[1] = vec4(spec, vertex_color.a); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl index 9fcee04c32..f693323d45 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl @@ -38,7 +38,7 @@ uniform sampler2D diffuseMap; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; -VARYING vec4 vary_position; +VARYING vec3 vary_position; uniform samplerCube environmentMap; @@ -74,7 +74,7 @@ void main() vec3 amblit; vec3 additive; vec3 atten; - vec3 pos = vary_position.xyz/vary_position.w; + vec3 pos = vary_position.xyz; calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false); diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl index 3bd6b693fa..5264b3b716 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl @@ -45,7 +45,7 @@ ATTRIBUTE vec2 texcoord0; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; -VARYING vec4 vary_position; +VARYING vec3 vary_position; #ifdef HAS_SKIN mat4 getObjectSkinnedTransform(); @@ -62,17 +62,23 @@ void main() mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; vec4 pos = mat * vert; - vary_position = gl_Position = projection_matrix * pos; + gl_Position = projection_matrix * pos; vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); #else vec4 pos = (modelview_matrix * vert); - vary_position = gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); + gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); vec3 norm = normalize(normal_matrix * normal); #endif - vec3 ref = reflect(pos.xyz, -norm); + vary_position = pos.xyz; vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vary_texcoord1 = (texture_matrix1 * vec4(ref,1.0)).xyz; + +#ifndef HAS_REFLECTION_PROBES + vec3 ref = reflect(pos.xyz, -norm); + vary_texcoord1 = transpose(normal_matrix) * ref.xyz; +#else + vary_texcoord1 = norm; +#endif calcAtmospherics(pos.xyz); diff --git a/indra/newview/app_settings/shaders/class1/deferred/highlightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/highlightF.glsl index 90566393d2..75f914cb02 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/highlightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/highlightF.glsl @@ -38,5 +38,5 @@ void main() { frag_data[0] = color*texture2D(diffuseMap, vary_texcoord0.xy); frag_data[1] = vec4(0.0); - frag_data[2] = vec4(0.0, 1.0, 0.0, 1.0); + frag_data[2] = vec4(0.0, 1.0, 0.0, GBUFFER_FLAG_SKIP_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index a58cc3d12d..67f4c59c3f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -56,5 +56,5 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = spec; - frag_data[2] = norm; + frag_data[2] = norm; // TODO: Should .w be set? } diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl index 02d83925ea..6f087632a5 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl @@ -277,10 +277,10 @@ void main() vec4 final_specular = spec; #ifdef HAS_SPECULAR_MAP - vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity * spec.a, 0.0); + vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity * spec.a, GBUFFER_FLAG_HAS_ATMOS); final_specular.a = specular_color.a * norm.a; #else - vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity, 0.0); + vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity, GBUFFER_FLAG_HAS_ATMOS); final_specular.a = specular_color.a; #endif @@ -444,10 +444,10 @@ void main() #else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer - // deferred path - frag_data[0] = final_color; //gbuffer is sRGB + // deferred path // See: C++: addDeferredAttachment(), shader: softenLightF.glsl + frag_data[0] = final_color; // gbuffer is sRGB frag_data[1] = final_specular; // XYZ = Specular color. W = Specular exponent. - frag_data[2] = final_normal; // XY = Normal. Z = Env. intensity. + frag_data[2] = final_normal; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog) #endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl index 7e29ada205..a1cab87092 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl @@ -1,5 +1,5 @@ /** - * @file bumpV.glsl + * @file materialV.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl b/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl index 35068899ee..a513d60388 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl @@ -66,7 +66,7 @@ void main() frag_data[0] = vec4(c.rgb, c.a); frag_data[1] = vec4(0.0); - frag_data[2] = vec4(0.0f); + frag_data[2] = vec4(0.0, 0.0, 0.0, GBUFFER_FLAG_HAS_ATMOS); gl_FragDepth = 0.999985f; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl index 09c47165dd..0ae4bbfc5d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl @@ -36,7 +36,6 @@ out vec4 frag_color; uniform sampler2DRect depthMap; uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; -uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D lightFunc; diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl index ec3fb9c543..8dcc18080d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl @@ -42,7 +42,6 @@ uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; -uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D projectionMap; uniform sampler2D lightFunc; diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl new file mode 100644 index 0000000000..b5c38bba04 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl @@ -0,0 +1,156 @@ +/** + * @file pbropaqueF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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]*/ + +#define DEBUG_PBR_LIGHT_TYPE 0 // Output Diffuse=0.75, Emissive=0, ORM=0,0,0 + +#define DEBUG_BASIC 0 +#define DEBUG_VERTEX 0 +#define DEBUG_NORMAL_MAP 0 // Output packed normal map "as is" to diffuse +#define DEBUG_NORMAL_OUT 0 // Output unpacked normal to diffuse +#define DEBUG_ORM 0 // Output Occlusion Roughness Metal "as is" to diffuse +#define DEBUG_POSITION 0 + +uniform sampler2D diffuseMap; //always in sRGB space + +uniform float metallicFactor; +uniform float roughnessFactor; +uniform vec3 emissiveColor; + +#ifdef HAS_NORMAL_MAP + uniform sampler2D bumpMap; +#endif + +#ifdef HAS_EMISSIVE_MAP + uniform sampler2D emissiveMap; +#endif + +#ifdef HAS_SPECULAR_MAP + uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness +#endif + +uniform samplerCube environmentMap; +uniform mat3 env_mat; + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[4]; +#else +#define frag_data gl_FragData +#endif + +VARYING vec3 vary_position; +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; +#ifdef HAS_NORMAL_MAP +VARYING vec3 vary_normal; +VARYING vec3 vary_mat0; +VARYING vec3 vary_mat1; +VARYING vec3 vary_mat2; +VARYING vec2 vary_texcoord1; +#endif + +#ifdef HAS_SPECULAR_MAP + VARYING vec2 vary_texcoord2; +#endif + +vec2 encode_normal(vec3 n); +vec3 linear_to_srgb(vec3 c); + +const float M_PI = 3.141592653589793; + +void main() +{ +// IF .mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; +// vec3 col = vertex_color.rgb * diffuseLookup(vary_texcoord0.xy).rgb; +// else + vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb; + +#ifdef HAS_NORMAL_MAP + vec4 norm = texture2D(bumpMap, vary_texcoord1.xy); + norm.xyz = norm.xyz * 2 - 1; + + vec3 tnorm = vec3(dot(norm.xyz,vary_mat0), + dot(norm.xyz,vary_mat1), + dot(norm.xyz,vary_mat2)); +#else + vec4 norm = vec4(0,0,0,1.0); +// vec3 tnorm = vary_normal; + vec3 tnorm = vec3(0,0,1); +#endif + + tnorm = normalize(tnorm.xyz); + + norm.xyz = normalize(tnorm.xyz); + + // RGB = Occlusion, Roughness, Metal + // default values, see LLViewerTexture::sDefaultPBRORMImagep + // occlusion 1.0 + // roughness 0.0 + // metal 0.0 +#ifdef HAS_SPECULAR_MAP + vec3 spec = texture2D(specularMap, vary_texcoord2.xy).rgb; +#else + vec3 spec = vec3(1,0,0); +#endif + + spec.g *= roughnessFactor; + spec.b *= metallicFactor; + + vec3 emissive = emissiveColor; +#ifdef HAS_EMISSIVE_MAP + emissive *= texture2D(emissiveMap, vary_texcoord0.xy).rgb; +#endif + +#if DEBUG_PBR_LIGHT_TYPE + col.rgb = vec3(0.75); + emissive = vec3(0); + spec.rgb = vec3(0); +#endif +#if DEBUG_BASIC + col.rgb = vec3( 1, 0, 1 ); +#endif +#if DEBUG_VERTEX + col.rgb = vertex_color.rgb; +#endif +#if DEBUG_NORMAL_MAP + col.rgb = texture2D(bumpMap, vary_texcoord1.xy).rgb; +#endif +#if DEBUG_NORMAL_OUT + col.rgb = vary_normal; +#endif +#if DEBUG_ORM + col.rgb = linear_to_srgb(spec); +#endif +#if DEBUG_POSITION + col.rgb = vary_position.xyz; +#endif + + // See: C++: addDeferredAttachments(), GLSL: softenLightF + frag_data[0] = vec4(col, 0.0); // Diffuse + frag_data[1] = vec4(emissive, vertex_color.a); // PBR sRGB Emissive + frag_data[2] = vec4(encode_normal(tnorm), vertex_color.a, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags + frag_data[3] = vec4(spec.rgb,0); // PBR linear packed Occlusion, Roughness, Metal. +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl new file mode 100644 index 0000000000..a2606ed771 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl @@ -0,0 +1,144 @@ +/** + * @file pbropaqueV.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +#define DIFFUSE_ALPHA_MODE_IGNORE 0 +#define DIFFUSE_ALPHA_MODE_BLEND 1 +#define DIFFUSE_ALPHA_MODE_MASK 2 +#define DIFFUSE_ALPHA_MODE_EMISSIVE 3 + +#ifdef HAS_SKIN +uniform mat4 modelview_matrix; +uniform mat4 projection_matrix; +mat4 getObjectSkinnedTransform(); +#else +uniform mat3 normal_matrix; +uniform mat4 modelview_projection_matrix; +#endif + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + +#if !defined(HAS_SKIN) +uniform mat4 modelview_matrix; +#endif + +VARYING vec3 vary_position; + +#endif + +uniform mat4 texture_matrix0; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec3 normal; +ATTRIBUTE vec2 texcoord0; + + +#ifdef HAS_NORMAL_MAP +ATTRIBUTE vec4 tangent; +ATTRIBUTE vec2 texcoord1; + +VARYING vec3 vary_mat0; +VARYING vec3 vary_mat1; +VARYING vec3 vary_mat2; + +VARYING vec2 vary_texcoord1; +#else +VARYING vec3 vary_normal; +#endif + +#ifdef HAS_SPECULAR_MAP +ATTRIBUTE vec2 texcoord2; +VARYING vec2 vary_texcoord2; +#endif + +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void main() +{ +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + + mat = modelview_matrix * mat; + + vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + vary_position = pos; +#endif + + gl_Position = projection_matrix*vec4(pos,1.0); + +#else + //transform vertex + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + +#endif + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + +#ifdef HAS_NORMAL_MAP + vary_texcoord1 = (texture_matrix0 * vec4(texcoord1,0,1)).xy; +#endif + +#ifdef HAS_SPECULAR_MAP + vary_texcoord2 = (texture_matrix0 * vec4(texcoord2,0,1)).xy; +#endif + +#ifdef HAS_SKIN + vec3 n = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); +#ifdef HAS_NORMAL_MAP + vec3 t = normalize((mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz); + vec3 b = cross(n, t)*tangent.w; + + vary_mat0 = vec3(t.x, b.x, n.x); + vary_mat1 = vec3(t.y, b.y, n.y); + vary_mat2 = vec3(t.z, b.z, n.z); +#else //HAS_NORMAL_MAP +vary_normal = n; +#endif //HAS_NORMAL_MAP +#else //HAS_SKIN + vec3 n = normalize(normal_matrix * normal); +#ifdef HAS_NORMAL_MAP + vec3 t = normalize(normal_matrix * tangent.xyz); + vec3 b = cross(n,t)*tangent.w; + //vec3 t = cross(b,n) * binormal.w; + + vary_mat0 = vec3(t.x, b.x, n.x); + vary_mat1 = vec3(t.y, b.y, n.y); + vary_mat2 = vec3(t.z, b.z, n.z); +#else //HAS_NORMAL_MAP + vary_normal = n; +#endif //HAS_NORMAL_MAP +#endif //HAS_SKIN + + vertex_color = diffuse_color; + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) +#if !defined(HAS_SKIN) + vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; +#endif +#endif +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl index 18616a9bb3..5bb034d5c1 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl @@ -1,5 +1,5 @@ /** - * @file pointLightF.glsl + * @file class1\deferred\pointLightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code @@ -36,7 +36,6 @@ out vec4 frag_color; uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect normalMap; -uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D lightFunc; uniform sampler2DRect depthMap; diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl b/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl index 345c07a354..8f3e38b08b 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl @@ -1,58 +1,44 @@ -/** - * @file shadowAlphaMaskF.glsl +/** + * @file class1/deferred/reflectionProbeF.glsl * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. - * + * Copyright (C) 2022, 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]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2D diffuseMap; - -#if !defined(DEPTH_CLAMP) -VARYING float pos_zd2; -#endif - -VARYING float pos_w; - -VARYING float target_pos_x; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; -VARYING vec3 pos; - -vec4 computeMoments(float depth, float a); - -void main() +// fallback stub -- will be used if actual reflection probe shader failed to load (output pink so it's obvious) +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec3 pos, vec3 norm, float glossiness, float envIntensity) { - float alpha = diffuseLookup(vary_texcoord0.xy).a * vertex_color.a; + ambenv = vec3(1,0,1); + glossenv = vec3(1,0,1); + legacyenv = vec3(1,0,1); +} - frag_color = computeMoments(length(pos), float a); +void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm) +{ + color = vec3(1,0,1); +} -#if !defined(DEPTH_CLAMP) - gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0); -#endif +void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity) +{ + color = vec3(1,0,1); } + diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl index 331249dc33..ecb0c43518 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl @@ -57,7 +57,7 @@ void main() /// Gamma correct for WL (soft clip effect). frag_data[0] = vec4(color.rgb, 0.0); frag_data[1] = vec4(0.0,0.0,0.0,0.0); - frag_data[2] = vec4(0.0,0.0,0.0,1.0); //1.0 in norm.w masks off fog + frag_data[2] = vec4(0.0,0.0,0.0,GBUFFER_FLAG_SKIP_ATMOS); //1.0 in norm.w masks off fog gl_FragDepth = 0.99999f; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl index 7f2c603f87..918e119c31 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl @@ -142,7 +142,7 @@ void main() color = mix(color.rgb, reflected_color, envIntensity); } - if (norm.w < 0.5) + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) { color = mix(atmosFragLighting(color, additive, atten), fullbrightAtmosTransportFrag(color, additive, atten), diffuse.a); color = mix(scaleSoftClipFrag(color), fullbrightScaleSoftClip(color), diffuse.a); diff --git a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl index bac79a9fdc..ef9cee3fa0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl @@ -60,7 +60,7 @@ void main() frag_data[0] = col; frag_data[1] = vec4(0.0f); - frag_data[2] = vec4(0.0, 1.0, 0.0, 1.0); + frag_data[2] = vec4(0.0, 1.0, 0.0, GBUFFER_FLAG_SKIP_ATMOS); gl_FragDepth = 0.99995f; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunDiscF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunDiscF.glsl index b2fa5d8a25..4ab8747629 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunDiscF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunDiscF.glsl @@ -57,7 +57,7 @@ void main() frag_data[0] = c; frag_data[1] = vec4(0.0f); - frag_data[2] = vec4(0.0, 1.0, 0.0, 1.0); + frag_data[2] = vec4(0.0, 1.0, 0.0, GBUFFER_FLAG_SKIP_ATMOS); gl_FragDepth = 0.999988f; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl index 6b6eed9db8..d6c14c48c9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl @@ -63,6 +63,6 @@ void main() frag_data[0] = outColor; frag_data[1] = vec4(0.0,0.0,0.0,-1.0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl index 89e354558a..dc0e5b0ce3 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl @@ -52,5 +52,5 @@ void main() frag_data[0] = vec4(vertex_color.rgb*col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl index 9a5debb3c1..14c337e608 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl @@ -78,5 +78,5 @@ void main() frag_data[0] = vec4(fb.rgb, 1.0); // diffuse frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec - frag_data[2] = vec4(encode_normal(wavef), 0.0, 0.0); // normalxyz, env intens, atmo kill + frag_data[2] = vec4(encode_normal(wavef), 0.0, GBUFFER_FLAG_HAS_ATMOS); // normalxyz, env intens, flags (atmo kill) } diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl index a157e9c017..03896f4c51 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl @@ -180,5 +180,5 @@ void main() frag_data[1] = vec4(0); // speccolor, spec - frag_data[2] = vec4(encode_normal(screenspacewavef.xyz), 0.05, 0);// normalxy, 0, 0 + frag_data[2] = vec4(encode_normal(screenspacewavef.xyz), 0.05, GBUFFER_FLAG_HAS_ATMOS);// normalxy, env intens, flags (atmo kill) } diff --git a/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl new file mode 100644 index 0000000000..4d91395a1b --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/irradianceGenF.glsl @@ -0,0 +1,100 @@ +/** + * @file irradianceGenF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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]*/ + + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform samplerCubeArray reflectionProbes; +uniform int sourceIdx; + +VARYING vec3 vary_dir; + +// ============================================================================================================= +// Parts of this file are (c) 2018 Sascha Willems +// SNIPPED FROM https://github.com/SaschaWillems/Vulkan-glTF-PBR/blob/master/data/shaders/irradiancecube.frag +/* +MIT License + +Copyright (c) 2018 Sascha Willems + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +// ============================================================================================================= + + + +#define PI 3.1415926535897932384626433832795 + +void main() +{ + float deltaPhi = (2.0 * PI) / 11.25; + float deltaTheta = (0.5 * PI) / 4.0; + float mipLevel = 2; + + vec3 N = normalize(vary_dir); + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = normalize(cross(up, N)); + up = cross(N, right); + + const float TWO_PI = PI * 2.0; + const float HALF_PI = PI * 0.5; + + vec3 color = vec3(0.0); + uint sampleCount = 0u; + for (float phi = 0.0; phi < TWO_PI; phi += deltaPhi) { + for (float theta = 0.0; theta < HALF_PI; theta += deltaTheta) { + vec3 tempVec = cos(phi) * right + sin(phi) * up; + vec3 sampleVector = cos(theta) * N + sin(theta) * tempVec; + color += textureLod(reflectionProbes, vec4(sampleVector, sourceIdx), mipLevel).rgb * cos(theta) * sin(theta); + sampleCount++; + } + } + frag_color = vec4(PI * color / float(sampleCount), 1.0); +} +// ============================================================================================================= + diff --git a/indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl b/indra/newview/app_settings/shaders/class1/interface/irradianceGenV.glsl index b466883dc7..5190abf17c 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/irradianceGenV.glsl @@ -1,9 +1,9 @@ /** - * @file genSkyShV.glsl + * @file irradianceGenV.glsl * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2005, Linden Research, Inc. + * Copyright (C) 2011, 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 @@ -22,16 +22,17 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + +uniform mat4 modelview_matrix; + ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; -VARYING vec2 vary_frag; +VARYING vec3 vary_dir; void main() { - // pass through untransformed fullscreen pos - gl_Position = vec4(position.xyz, 1.0); - vary_frag = texcoord0; + gl_Position = vec4(position, 1.0); + + vary_dir = vec3(modelview_matrix * vec4(position, 1.0)).xyz; } diff --git a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl new file mode 100644 index 0000000000..94fedce243 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl @@ -0,0 +1,168 @@ +/** + * @file radianceGenF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform samplerCubeArray reflectionProbes; +uniform int sourceIdx; + +VARYING vec3 vary_dir; + +// ============================================================================================================= +// Parts of this file are (c) 2018 Sascha Willems +// SNIPPED FROM https://github.com/SaschaWillems/Vulkan-glTF-PBR/blob/master/data/shaders/prefilterenvmap.frag +/* +MIT License + +Copyright (c) 2018 Sascha Willems + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +// ============================================================================================================= + + +uniform float roughness; + +uniform float mipLevel; + +const float PI = 3.1415926536; + +// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ +float random(vec2 co) +{ + float a = 12.9898; + float b = 78.233; + float c = 43758.5453; + float dt= dot(co.xy ,vec2(a,b)); + float sn= mod(dt,3.14); + return fract(sin(sn) * c); +} + +vec2 hammersley2d(uint i, uint N) +{ + // Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + uint bits = (i << 16u) | (i >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + float rdi = float(bits) * 2.3283064365386963e-10; + return vec2(float(i) /float(N), rdi); +} + +// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf +vec3 importanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +{ + // Maps a 2D point to a hemisphere with spread based on roughness + float alpha = roughness * roughness; + float phi = 2.0 * PI * Xi.x + random(normal.xz) * 0.1; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + + // Tangent space + vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(up, normal)); + vec3 tangentY = normalize(cross(normal, tangentX)); + + // Convert to world Space + return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); +} + +// Normal Distribution function +float D_GGX(float dotNH, float roughness) +{ + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); +} + +vec3 prefilterEnvMap(vec3 R, float roughness) +{ + vec3 N = R; + vec3 V = R; + vec3 color = vec3(0.0); + float totalWeight = 0.0; + float envMapDim = 256.0; + int numSamples = 32/max(int(mipLevel), 1); + + for(uint i = 0u; i < numSamples; i++) { + vec2 Xi = hammersley2d(i, numSamples); + vec3 H = importanceSample_GGX(Xi, roughness, N); + vec3 L = 2.0 * dot(V, H) * H - V; + float dotNL = clamp(dot(N, L), 0.0, 1.0); + if(dotNL > 0.0) { + // Filtering based on https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/ + + float dotNH = clamp(dot(N, H), 0.0, 1.0); + float dotVH = clamp(dot(V, H), 0.0, 1.0); + + // Probability Distribution Function + float pdf = D_GGX(dotNH, roughness) * dotNH / (4.0 * dotVH) + 0.0001; + // Slid angle of current smple + float omegaS = 1.0 / (float(numSamples) * pdf); + // Solid angle of 1 pixel across all cube faces + float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim); + // Biased (+1.0) mip level for better result + //float mipLevel = roughness == 0.0 ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f); + color += textureLod(reflectionProbes, vec4(L,sourceIdx), mipLevel).rgb * dotNL; + totalWeight += dotNL; + + } + } + return (color / totalWeight); +} + +void main() +{ + vec3 N = normalize(vary_dir); + frag_color = vec4(prefilterEnvMap(N, roughness), 1.0); +} +// ============================================================================================================= + diff --git a/indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl b/indra/newview/app_settings/shaders/class1/interface/radianceGenV.glsl index 8f32dfde79..5f5d9396ff 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/radianceGenV.glsl @@ -1,9 +1,9 @@ /** - * @file class3/deferred/shVisV.glsl + * @file radianceGenV.glsl * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2007, Linden Research, Inc. + * Copyright (C) 2011, 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 @@ -22,12 +22,17 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ + +uniform mat4 modelview_matrix; + ATTRIBUTE vec3 position; -VARYING vec4 vary_pos; + +VARYING vec3 vary_dir; void main() { - // Output - vary_pos = vec4(position, 1); - gl_Position = vary_pos; + gl_Position = vec4(position, 1.0); + + vary_dir = vec3(modelview_matrix * vec4(position, 1.0)).xyz; } + diff --git a/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl b/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl new file mode 100644 index 0000000000..ea687aab4f --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl @@ -0,0 +1,75 @@ +/** + * @file reflectionmipF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +#extension GL_ARB_texture_rectangle : enable + +/*[EXTRA_CODE_HERE]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect screenMap; + +VARYING vec2 vary_texcoord0; + +void main() +{ + float w[9]; + + float c = 1.0/16.0; //corner weight + float e = 1.0/8.0; //edge weight + float m = 1.0/4.0; //middle weight + + //float wsum = c*4+e*4+m; + + w[0] = c; w[1] = e; w[2] = c; + w[3] = e; w[4] = m; w[5] = e; + w[6] = c; w[7] = e; w[8] = c; + + vec2 tc[9]; + + float ed = 1; + float cd = 1; + + + tc[0] = vec2(-cd, cd); tc[1] = vec2(0, ed); tc[2] = vec2(cd, cd); + tc[3] = vec2(-ed, 0); tc[4] = vec2(0, 0); tc[5] = vec2(ed, 0); + tc[6] = vec2(-cd, -cd); tc[7] = vec2(0, -ed); tc[8] = vec2(cd, -1); + + vec3 color = vec3(0,0,0); + + for (int i = 0; i < 9; ++i) + { + color += texture2DRect(screenMap, vary_texcoord0.xy+tc[i]).rgb * w[i]; + //color += texture2DRect(screenMap, vary_texcoord0.xy+tc[i]*2.0).rgb * w[i]*0.5; + } + + //color /= wsum; + + frag_color = vec4(color, 1.0); +} diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl index ea2690ba09..3831eeaa01 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl @@ -43,6 +43,7 @@ uniform float sun_moon_glow_factor; float getAmbientClamp() { return 1.0f; } +// Returns colors in sRGB void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao) { diff --git a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl new file mode 100644 index 0000000000..ab5badf538 --- /dev/null +++ b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl @@ -0,0 +1,477 @@ +/** + * @file class2/deferred/reflectionProbeF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +#extension GL_ARB_shader_texture_lod : enable + +#define FLT_MAX 3.402823466e+38 + +#define REFMAP_COUNT 256 +#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider + +uniform samplerCubeArray reflectionProbes; + +layout (std140, binding = 1) uniform ReflectionProbes +{ + // list of OBBs for user override probes + // box is a set of 3 planes outward facing planes and the depth of the box along that plane + // for each box refBox[i]... + /// box[0..2] - plane 0 .. 2 in [A,B,C,D] notation + // box[3][0..2] - plane thickness + mat4 refBox[REFMAP_COUNT]; + // list of bounding spheres for reflection probes sorted by distance to camera (closest first) + vec4 refSphere[REFMAP_COUNT]; + // index of cube map in reflectionProbes for a corresponding reflection probe + // e.g. cube map channel of refSphere[2] is stored in refIndex[2] + // refIndex.x - cubemap channel in reflectionProbes + // refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index) + // refIndex.z - number of neighbors + // refIndex.w - priority, if negative, this probe has a box influence + ivec4 refIndex[REFMAP_COUNT]; + + // neighbor list data (refSphere indices, not cubemap array layer) + ivec4 refNeighbor[1024]; + + // number of reflection probes present in refSphere + int refmapCount; + + // intensity of ambient light from reflection probes + float reflectionAmbiance; +}; + +// Inputs +uniform mat3 env_mat; + +// list of probeIndexes shader will actually use after "getRefIndex" is called +// (stores refIndex/refSphere indices, NOT rerflectionProbes layer) +int probeIndex[REF_SAMPLE_COUNT]; + +// number of probes stored in probeIndex +int probeInfluences = 0; + +bool isAbove(vec3 pos, vec4 plane) +{ + return (dot(plane.xyz, pos) + plane.w) > 0; +} + +// return true if probe at index i influences position pos +bool shouldSampleProbe(int i, vec3 pos) +{ + if (refIndex[i].w < 0) + { + vec4 v = refBox[i] * vec4(pos, 1.0); + if (abs(v.x) > 1 || + abs(v.y) > 1 || + abs(v.z) > 1) + { + return false; + } + } + else + { + vec3 delta = pos.xyz - refSphere[i].xyz; + float d = dot(delta, delta); + float r2 = refSphere[i].w; + r2 *= r2; + + if (d > r2) + { //outside bounding sphere + return false; + } + } + + return true; +} + +// call before sampleRef +// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT +// overall algorithm -- +void preProbeSample(vec3 pos) +{ + // TODO: make some sort of structure that reduces the number of distance checks + + for (int i = 0; i < refmapCount; ++i) + { + // found an influencing probe + if (shouldSampleProbe(i, pos)) + { + probeIndex[probeInfluences] = i; + ++probeInfluences; + + int neighborIdx = refIndex[i].y; + if (neighborIdx != -1) + { + int neighborCount = min(refIndex[i].z, REF_SAMPLE_COUNT-1); + + int count = 0; + while (count < neighborCount) + { + // check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index) + + int idx = refNeighbor[neighborIdx].x; + if (shouldSampleProbe(idx, pos)) + { + probeIndex[probeInfluences++] = idx; + if (probeInfluences == REF_SAMPLE_COUNT) + { + return; + } + } + count++; + if (count == neighborCount) + { + return; + } + + idx = refNeighbor[neighborIdx].y; + if (shouldSampleProbe(idx, pos)) + { + probeIndex[probeInfluences++] = idx; + if (probeInfluences == REF_SAMPLE_COUNT) + { + return; + } + } + count++; + if (count == neighborCount) + { + return; + } + + idx = refNeighbor[neighborIdx].z; + if (shouldSampleProbe(idx, pos)) + { + probeIndex[probeInfluences++] = idx; + if (probeInfluences == REF_SAMPLE_COUNT) + { + return; + } + } + count++; + if (count == neighborCount) + { + return; + } + + idx = refNeighbor[neighborIdx].w; + if (shouldSampleProbe(idx, pos)) + { + probeIndex[probeInfluences++] = idx; + if (probeInfluences == REF_SAMPLE_COUNT) + { + return; + } + } + count++; + if (count == neighborCount) + { + return; + } + + ++neighborIdx; + } + + return; + } + } + } +} + +// from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection + +// original reference implementation: +/* +bool intersect(const Ray &ray) const +{ + float t0, t1; // solutions for t if the ray intersects +#if 0 + // geometric solution + Vec3f L = center - orig; + float tca = L.dotProduct(dir); + // if (tca < 0) return false; + float d2 = L.dotProduct(L) - tca * tca; + if (d2 > radius2) return false; + float thc = sqrt(radius2 - d2); + t0 = tca - thc; + t1 = tca + thc; +#else + // analytic solution + Vec3f L = orig - center; + float a = dir.dotProduct(dir); + float b = 2 * dir.dotProduct(L); + float c = L.dotProduct(L) - radius2; + if (!solveQuadratic(a, b, c, t0, t1)) return false; +#endif + if (t0 > t1) std::swap(t0, t1); + + if (t0 < 0) { + t0 = t1; // if t0 is negative, let's use t1 instead + if (t0 < 0) return false; // both t0 and t1 are negative + } + + t = t0; + + return true; +} */ + +// adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere +vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2) +{ + float t0, t1; // solutions for t if the ray intersects + + vec3 L = center - origin; + float tca = dot(L,dir); + + float d2 = dot(L,L) - tca * tca; + + float thc = sqrt(radius2 - d2); + t0 = tca - thc; + t1 = tca + thc; + + vec3 v = origin + dir * t1; + return v; +} + +// from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ +/* +vec3 DirectionWS = normalize(PositionWS - CameraWS); +vec3 ReflDirectionWS = reflect(DirectionWS, NormalWS); + +// Intersection with OBB convertto unit box space +// Transform in local unit parallax cube space (scaled and rotated) +vec3 RayLS = MulMatrix( float(3x3)WorldToLocal, ReflDirectionWS); +vec3 PositionLS = MulMatrix( WorldToLocal, PositionWS); + +vec3 Unitary = vec3(1.0f, 1.0f, 1.0f); +vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS; +vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS; +vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect); +float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z)); + +// Use Distance in WS directly to recover intersection +vec3 IntersectPositionWS = PositionWS + ReflDirectionWS * Distance; +vec3 ReflDirectionWS = IntersectPositionWS - CubemapPositionWS; + +return texCUBE(envMap, ReflDirectionWS); +*/ + +// get point of intersection with given probe's box influence volume +// origin - ray origin in clip space +// dir - ray direction in clip space +// i - probe index in refBox/refSphere +vec3 boxIntersect(vec3 origin, vec3 dir, int i) +{ + // Intersection with OBB convertto unit box space + // Transform in local unit parallax cube space (scaled and rotated) + mat4 clipToLocal = refBox[i]; + + vec3 RayLS = mat3(clipToLocal) * dir; + vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz; + + vec3 Unitary = vec3(1.0f, 1.0f, 1.0f); + vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS; + vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS; + vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect); + float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z)); + + // Use Distance in CS directly to recover intersection + vec3 IntersectPositionCS = origin + dir * Distance; + + return IntersectPositionCS; +} + + + +// Tap a sphere based reflection probe +// pos - position of pixel +// dir - pixel normal +// lod - which mip to bias towards (lower is higher res, sharper reflections) +// c - center of probe +// r2 - radius of probe squared +// i - index of probe +// vi - point at which reflection vector struck the influence volume, in clip space +vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i) +{ + //lod = max(lod, 1); + // parallax adjustment + + vec3 v; + if (refIndex[i].w < 0) + { + v = boxIntersect(pos, dir, i); + } + else + { + v = sphereIntersect(pos, dir, c, r2); + } + + v -= c; + v = env_mat * v; + { + float min_lod = textureQueryLod(reflectionProbes,v).y; // lower is higher res + return textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), max(min_lod, lod)).rgb; + //return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb; + } +} + +vec3 sampleProbes(vec3 pos, vec3 dir, float lod) +{ + float wsum = 0.0; + vec3 col = vec3(0,0,0); + float vd2 = dot(pos,pos); // view distance squared + + for (int idx = 0; idx < probeInfluences; ++idx) + { + int i = probeIndex[idx]; + float r = refSphere[i].w; // radius of sphere volume + float p = float(abs(refIndex[i].w)); // priority + float rr = r*r; // radius squred + float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down) + vec3 delta = pos.xyz-refSphere[i].xyz; + float d2 = dot(delta,delta); + float r2 = r1*r1; + + { + vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i); + + float w = 1.0/d2; + + float atten = 1.0-max(d2-r2, 0.0)/(rr-r2); + w *= atten; + w *= p; // boost weight based on priority + col += refcol*w; + + wsum += w; + } + } + + if (probeInfluences <= 1) + { //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera + for (int idx = 0; idx < 8; ++idx) + { + if (refIndex[idx].w < 0) + { // don't fallback to box probes, they are *very* specific + continue; + } + int i = idx; + vec3 delta = pos.xyz-refSphere[i].xyz; + float d2 = dot(delta,delta); + + { + vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i); + + float w = 1.0/d2; + w *= w; + col += refcol*w; + wsum += w; + } + } + } + + if (wsum > 0.0) + { + col *= 1.0/wsum; + } + + return col; +} + +vec3 sampleProbeAmbient(vec3 pos, vec3 dir, float lod) +{ + vec3 col = sampleProbes(pos, dir, lod); + + //desaturate + vec3 hcol = col *0.5; + + col *= 2.0; + col = vec3( + col.r + hcol.g + hcol.b, + col.g + hcol.r + hcol.b, + col.b + hcol.r + hcol.g + ); + + col *= 0.333333; + + return col*reflectionAmbiance; + +} + +// brighten a color so that at least one component is 1 +vec3 brighten(vec3 c) +{ + float m = max(max(c.r, c.g), c.b); + + if (m == 0) + { + return vec3(1,1,1); + } + + return c * 1.0/m; +} + + +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec3 pos, vec3 norm, float glossiness, float envIntensity) +{ + // TODO - don't hard code lods + float reflection_lods = 8; + preProbeSample(pos); + + vec3 refnormpersp = reflect(pos.xyz, norm.xyz); + + ambenv = sampleProbeAmbient(pos, norm, reflection_lods-1); + + if (glossiness > 0.0) + { + float lod = (1.0-glossiness)*reflection_lods; + glossenv = sampleProbes(pos, normalize(refnormpersp), lod); + } + + if (envIntensity > 0.0) + { + legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0); + } +} + +void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm) +{ + glossenv *= 0.35; // fudge darker + float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz); + float minf = spec.a * 0.1; + fresnel = fresnel * (1.0-minf) + minf; + glossenv *= spec.rgb*min(fresnel, 1.0); + color.rgb += glossenv; +} + + void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity) + { + vec3 reflected_color = legacyenv; //*0.5; //fudge darker + vec3 lookAt = normalize(pos); + float fresnel = 1.0+dot(lookAt, norm.xyz); + fresnel *= fresnel; + fresnel = min(fresnel+envIntensity, 1.0); + reflected_color *= (envIntensity*fresnel)*brighten(spec.rgb); + color = mix(color.rgb, reflected_color, envIntensity); + } + diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl index 6841a8194f..4379024680 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl @@ -195,5 +195,5 @@ void main() // Gamma correct for WL (soft clip effect). frag_data[0] = vec4(color.rgb, 1.0); frag_data[1] = vec4(0.0, 0.0, 0.0, 0.0); - frag_data[2] = vec4(0.0, 0.0, 0.0, 1.0); // 1.0 in norm.w masks off fog + frag_data[2] = vec4(0.0, 0.0, 0.0, GBUFFER_FLAG_SKIP_ATMOS); // 1.0 in norm.w masks off fog } diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl index 7700d16007..677c9c244c 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl @@ -88,7 +88,7 @@ void main() da = pow(da, light_gamma); vec4 diffuse = texture2DRect(diffuseRect, tc); - diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14025 + diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14035 vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; @@ -139,7 +139,7 @@ void main() color = mix(color.rgb, reflected_color, envIntensity); } - if (norm.w < 0.5) + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) { color = mix(atmosFragLighting(color, additive, atten), fullbrightAtmosTransportFrag(color, additive, atten), diffuse.a); color = mix(scaleSoftClipFrag(color), fullbrightScaleSoftClip(color), diffuse.a); diff --git a/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowF.glsl b/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowF.glsl deleted file mode 100644 index d973326f93..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowF.glsl +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file avatarShadowF.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2D diffuseMap; - -VARYING vec4 pos; -VARYING vec2 vary_texcoord0; - -vec4 computeMoments(float depth, float a); - -void main() -{ - frag_color = computeMoments(length(pos), 1.0); -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowV.glsl deleted file mode 100644 index 1a655e6467..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/attachmentShadowV.glsl +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file attachmentShadowV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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 projection_matrix; -uniform mat4 modelview_matrix; -uniform mat4 texture_matrix0; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; - -mat4 getObjectSkinnedTransform(); - -VARYING vec4 pos; - -void main() -{ - //transform vertex - mat4 mat = getObjectSkinnedTransform(); - - mat = modelview_matrix * mat; - pos = (mat*vec4(position.xyz, 1.0)); - pos = projection_matrix * vec4(pos.xyz, 1.0); - -#if !defined(DEPTH_CLAMP) - pos.z = max(pos.z, -pos.w+0.01); -#endif - gl_Position = pos; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/avatarShadowV.glsl deleted file mode 100644 index 164b355f20..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/avatarShadowV.glsl +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file avatarShadowV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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 projection_matrix; - -mat4 getSkinnedTransform(); - -ATTRIBUTE vec3 position; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec2 texcoord0; - -#if !defined(DEPTH_CLAMP) -VARYING vec4 post_pos; -#endif - -VARYING vec4 pos; - -void main() -{ - vec3 norm; - - vec4 pos_in = vec4(position.xyz, 1.0); - mat4 trans = getSkinnedTransform(); - - pos.x = dot(trans[0], pos_in); - pos.y = dot(trans[1], pos_in); - pos.z = dot(trans[2], pos_in); - pos.w = 1.0; - - norm.x = dot(trans[0].xyz, normal); - norm.y = dot(trans[1].xyz, normal); - norm.z = dot(trans[2].xyz, normal); - norm = normalize(norm); - - pos = projection_matrix * pos; - -#if !defined(DEPTH_CLAMP) - post_pos = pos; - gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); -#else - gl_Position = pos; -#endif - -} - - diff --git a/indra/newview/app_settings/shaders/class3/deferred/cloudShadowF.glsl b/indra/newview/app_settings/shaders/class3/deferred/cloudShadowF.glsl deleted file mode 100644 index 32210f60dc..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/cloudShadowF.glsl +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @file class3/deferred/cloudsF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2D diffuseMap; - -VARYING vec4 pos; -VARYING float target_pos_x; -VARYING float vary_CloudDensity; -VARYING vec2 vary_texcoord0; -VARYING vec2 vary_texcoord1; -VARYING vec2 vary_texcoord2; -VARYING vec2 vary_texcoord3; - -uniform sampler2D cloud_noise_texture; -uniform sampler2D cloud_noise_texture_next; -uniform float blend_factor; -uniform vec4 cloud_pos_density1; -uniform vec4 cloud_pos_density2; -uniform vec4 cloud_color; -uniform float cloud_shadow; -uniform float cloud_scale; -uniform float cloud_variance; -uniform vec3 camPosLocal; -uniform vec3 sun_dir; -uniform float sun_size; -uniform float far_z; - -vec4 cloudNoise(vec2 uv) -{ - vec4 a = texture2D(cloud_noise_texture, uv); - vec4 b = texture2D(cloud_noise_texture_next, uv); - vec4 cloud_noise_sample = mix(a, b, blend_factor); - return normalize(cloud_noise_sample); -} - -vec4 computeMoments(float depth, float alpha); - -void main() -{ - if (cloud_scale >= 0.001) - { - // Set variables - vec2 uv1 = vary_texcoord0.xy; - vec2 uv2 = vary_texcoord1.xy; - vec2 uv3 = vary_texcoord2.xy; - float cloudDensity = 2.0 * (cloud_shadow - 0.25); - - vec2 uv4 = vary_texcoord3.xy; - - vec2 disturbance = vec2(cloudNoise(uv1 / 8.0f).x, cloudNoise((uv3 + uv1) / 16.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); - vec2 disturbance2 = vec2(cloudNoise((uv1 + uv3) / 4.0f).x, cloudNoise((uv4 + uv2) / 8.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); - - // Offset texture coords - uv1 += cloud_pos_density1.xy + (disturbance * 0.2); //large texture, visible density - uv2 += cloud_pos_density1.xy; //large texture, self shadow - uv3 += cloud_pos_density2.xy; //small texture, visible density - uv4 += cloud_pos_density2.xy; //small texture, self shadow - - float density_variance = min(1.0, (disturbance.x* 2.0 + disturbance.y* 2.0 + disturbance2.x + disturbance2.y) * 4.0); - - cloudDensity *= 1.0 - (density_variance * density_variance); - - // Compute alpha1, the main cloud opacity - float alpha1 = (cloudNoise(uv1).x - 0.5) + (cloudNoise(uv3).x - 0.5) * cloud_pos_density2.z; - alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10 * cloud_pos_density1.z, 1.); - - // And smooth - alpha1 = 1. - alpha1 * alpha1; - alpha1 = 1. - alpha1 * alpha1; - - if (alpha1 < 0.001f) - { - discard; - } - - // Compute alpha2, for self shadowing effect - // (1 - alpha2) will later be used as percentage of incoming sunlight - float alpha2 = (cloudNoise(uv2).x - 0.5); - alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); - - // And smooth - alpha2 = 1. - alpha2; - alpha2 = 1. - alpha2 * alpha2; - - frag_color = computeMoments(length(pos), alpha1); - } - else - { - frag_color = vec4(0); - } -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/cloudShadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/cloudShadowV.glsl deleted file mode 100644 index effb070f93..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/cloudShadowV.glsl +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file cloudShadowV.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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 texture_matrix0; -uniform mat4 modelview_projection_matrix; -uniform float shadow_target_width; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; - -#if !defined(DEPTH_CLAMP) -VARYING float pos_zd2; -#endif - -VARYING vec4 pos; -VARYING float target_pos_x; -VARYING vec2 vary_texcoord0; -VARYING vec4 vertex_color; - -void passTextureIndex(); - -void main() -{ - //transform vertex - vec4 pre_pos = vec4(position.xyz, 1.0); - pos = modelview_projection_matrix * pre_pos; - target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; - -#if !defined(DEPTH_CLAMP) - pos_zd2 = pos.z * 0.5; - gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); -#else - gl_Position = pos; -#endif - - passTextureIndex(); - - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vertex_color = diffuse_color; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/cloudsF.glsl b/indra/newview/app_settings/shaders/class3/deferred/cloudsF.glsl deleted file mode 100644 index e40d7e7c75..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/cloudsF.glsl +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @file class3/deferred/cloudsF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_data[3]; -#else -#define frag_data gl_FragData -#endif - -///////////////////////////////////////////////////////////////////////// -// The fragment shader for the sky -///////////////////////////////////////////////////////////////////////// - -VARYING vec4 vary_CloudColorSun; -VARYING vec4 vary_CloudColorAmbient; -VARYING float vary_CloudDensity; -VARYING vec2 vary_texcoord0; -VARYING vec2 vary_texcoord1; -VARYING vec2 vary_texcoord2; -VARYING vec2 vary_texcoord3; -VARYING vec3 vary_pos; - -uniform sampler2D cloud_noise_texture; -uniform sampler2D cloud_noise_texture_next; -uniform float blend_factor; -uniform vec4 cloud_pos_density1; -uniform vec4 cloud_pos_density2; -uniform vec4 cloud_color; -uniform float cloud_shadow; -uniform float cloud_scale; -uniform float cloud_variance; -uniform vec3 camPosLocal; -uniform vec3 sun_dir; -uniform float sun_size; -uniform float far_z; - -uniform sampler2D transmittance_texture; -uniform sampler3D scattering_texture; -uniform sampler3D single_mie_scattering_texture; -uniform sampler2D irradiance_texture; -uniform sampler2D sh_input_r; -uniform sampler2D sh_input_g; -uniform sampler2D sh_input_b; - -vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance); - -/// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light); - -vec4 cloudNoise(vec2 uv) -{ - vec4 a = texture2D(cloud_noise_texture, uv); - vec4 b = texture2D(cloud_noise_texture_next, uv); - vec4 cloud_noise_sample = mix(a, b, blend_factor); - return cloud_noise_sample; -} - -void main() -{ - // Set variables - vec2 uv1 = vary_texcoord0.xy; - vec2 uv2 = vary_texcoord1.xy; - vec2 uv3 = vary_texcoord2.xy; - float cloudDensity = 2.0 * (cloud_shadow - 0.25); - - if (cloud_scale < 0.001) - { - discard; - } - - vec2 uv4 = vary_texcoord3.xy; - - vec2 disturbance = vec2(cloudNoise(uv1 / 16.0f).x, cloudNoise((uv3 + uv1) / 16.0f).x) * cloud_variance * (1.0f - cloud_scale * 0.25f); - - // Offset texture coords - uv1 += cloud_pos_density1.xy + (disturbance * 0.2); //large texture, visible density - uv2 += cloud_pos_density1.xy; //large texture, self shadow - uv3 += cloud_pos_density2.xy; //small texture, visible density - uv4 += cloud_pos_density2.xy; //small texture, self shadow - - float density_variance = min(1.0, (disturbance.x* 2.0 + disturbance.y* 2.0) * 4.0); - - cloudDensity *= 1.0 - (density_variance * density_variance); - - // Compute alpha1, the main cloud opacity - float alpha1 = (cloudNoise(uv1).x - 0.5) + (cloudNoise(uv3).x - 0.5) * cloud_pos_density2.z; - alpha1 = min(max(alpha1 + cloudDensity, 0.) * 10 * cloud_pos_density1.z, 1.); - - // And smooth - alpha1 = 1. - alpha1 * alpha1; - alpha1 = 1. - alpha1 * alpha1; - - if (alpha1 < 0.001f) - { - discard; - } - - // Compute alpha2, for self shadowing effect - // (1 - alpha2) will later be used as percentage of incoming sunlight - float alpha2 = (cloudNoise(uv2).x - 0.5); - alpha2 = min(max(alpha2 + cloudDensity, 0.) * 2.5 * cloud_pos_density1.z, 1.); - - // And smooth - alpha2 = 1. - alpha2; - alpha2 = 1. - alpha2 * alpha2; - - vec3 view_ray = vary_pos.xyz + camPosLocal; - - vec3 view_direction = normalize(view_ray); - vec3 sun_direction = normalize(sun_dir); - vec3 earth_center = vec3(0, 0, -6360.0f); - vec3 camPos = (camPosLocal / 1000.0f) - earth_center; - - vec3 transmittance; - vec3 radiance_sun = GetSkyLuminance(camPos, view_direction, 1.0 - alpha1, sun_direction, transmittance); - - vec3 sun_color = vec3(1.0) - exp(-radiance_sun * 0.0001); - - // Combine - vec4 color; - - vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265)); - - vec4 l1r = texture2D(sh_input_r, vec2(0,0)); - vec4 l1g = texture2D(sh_input_g, vec2(0,0)); - vec4 l1b = texture2D(sh_input_b, vec2(0,0)); - - vec3 sun_indir = vec3(-view_direction.xy, view_direction.z); - vec3 amb = vec3(dot(l1r, l1tap * vec4(1, sun_indir)), - dot(l1g, l1tap * vec4(1, sun_indir)), - dot(l1b, l1tap * vec4(1, sun_indir))); - - - amb = max(vec3(0), amb); - - color.rgb = sun_color * cloud_color.rgb * (1. - alpha2); - color.rgb = pow(color.rgb, vec3(1.0 / 2.2)); - color.rgb += amb; - - frag_data[0] = vec4(color.rgb, alpha1); - frag_data[1] = vec4(0); - frag_data[2] = vec4(0,1,0,1); -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/cloudsV.glsl b/indra/newview/app_settings/shaders/class3/deferred/cloudsV.glsl deleted file mode 100644 index 71e422ddf0..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/cloudsV.glsl +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file WLCloudsV.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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; -uniform mat4 modelview_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; - -////////////////////////////////////////////////////////////////////////// -// The vertex shader for creating the atmospheric sky -/////////////////////////////////////////////////////////////////////////////// - -// Output parameters -VARYING vec2 vary_texcoord0; -VARYING vec2 vary_texcoord1; -VARYING vec2 vary_texcoord2; -VARYING vec2 vary_texcoord3; -VARYING vec3 vary_pos; - -// Inputs -uniform float cloud_scale; -uniform vec4 lightnorm; -uniform vec3 camPosLocal; - -void main() -{ - vary_pos = position; - - // World / view / projection - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - - // Texture coords - vary_texcoord0 = texcoord0; - vary_texcoord0.xy -= 0.5; - vary_texcoord0.xy /= max(0.001, cloud_scale); - vary_texcoord0.xy += 0.5; - - vary_texcoord1 = vary_texcoord0; - vary_texcoord1.x += lightnorm.x * 0.0125; - vary_texcoord1.y += lightnorm.z * 0.0125; - - vary_texcoord2 = vary_texcoord0 * 16.; - vary_texcoord3 = vary_texcoord1 * 16.; - - // END CLOUDS -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl deleted file mode 100644 index e27bbce094..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file class1/deferred/deferredUtil.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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 sampler2DRect normalMap; -uniform sampler2DRect depthMap; - -uniform mat4 inv_proj; -uniform vec2 screen_res; - -vec2 getScreenCoordinate(vec2 screenpos) -{ - vec2 sc = screenpos.xy * 2.0; - if (screen_res.x > 0 && screen_res.y > 0) - { - sc /= screen_res; - } - return sc - vec2(1.0, 1.0); -} - -vec3 getNorm(vec2 screenpos) -{ - vec2 enc = texture2DRect(normalMap, screenpos.xy).xy; - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return n; -} - -float getDepth(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen).r; - return depth; -} - -vec4 getPosition(vec2 pos_screen) -{ - float depth = getDepth(pos_screen); - vec2 sc = getScreenCoordinate(pos_screen); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -vec4 getPositionWithDepth(vec2 pos_screen, float depth) -{ - vec2 sc = getScreenCoordinate(pos_screen); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl b/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl deleted file mode 100644 index cdaff4b09f..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl +++ /dev/null @@ -1,202 +0,0 @@ -/** - * @file depthToShadowVolumeG.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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$ - */ -#extension GL_ARB_geometry_shader4 : enable -#extension GL_ARB_texture_rectangle : enable - -/*[EXTRA_CODE_HERE]*/ - -layout (triangles) in; -layout (triangle_strip, max_vertices = 128) out; - -uniform sampler2DRect depthMap; -uniform mat4 shadowMatrix[6]; -uniform vec4 lightpos; - -VARYING vec2 vary_texcoord0; - -out vec3 to_vec; - -void cross_products(out vec4 ns[3], int a, int b, int c) -{ - ns[0] = cross(gl_PositionIn[b].xyz - gl_PositionIn[a].xyz, gl_PositionIn[c].xyz - gl_PositionIn[a].xyz); - ns[1] = cross(gl_PositionIn[c].xyz - gl_PositionIn[b].xyz, gl_PositionIn[a].xyz - gl_PositionIn[b].xyz); - ns[2] = cross(gl_PositionIn[a].xyz - gl_PositionIn[c].xyz, gl_PositionIn[b].xyz - gl_PositionIn[c].xyz); -} - -vec3 getLightDirection(vec4 lightpos, vec3 pos) -{ - - vec3 lightdir = lightpos.xyz - lightpos.w * pos; - return lightdir; -} - -void emitTri(vec4 v[3]) -{ - gl_Position = proj_matrix * v[0]; - EmitVertex(); - - gl_Position = proj_matrix * v[1]; - EmitVertex(); - - gl_Position = proj_matrix * v[2]; - EmitVertex(); - - EndPrimitive(); -} - -void emitQuad(vec4 v[4] -{ - // Emit a quad as a triangle strip. - gl_Position = proj_matrix*v[0]; - EmitVertex(); - - gl_Position = proj_matrix*v[1]; - EmitVertex(); - - gl_Position = proj_matrix*v[2]; - EmitVertex(); - - gl_Position = proj_matrix*v[3]; - EmitVertex(); - - EndPrimitive(); -} - -void emitPrimitives(int layer) -{ - int i = layer; - gl_Layer = i; - - vec4 depth1 = vec4(texture2DRect(depthMap, tc0).rg, texture2DRect(depthMap, tc1).rg)); - vec3 depth2 = vec4(texture2DRect(depthMap, tc2).rg, texture2DRect(depthMap, tc3).rg)); - vec3 depth3 = vec4(texture2DRect(depthMap, tc4).rg, texture2DRect(depthMap, tc5).rg)); - vec3 depth4 = vec4(texture2DRect(depthMap, tc6).rg, texture2DRect(depthMap, tc7).rg)); - - depth1 = min(depth1, depth2); - depth1 = min(depth1, depth3); - depth1 = min(depth1, depth4); - - vec2 depth = min(depth1.xy, depth1.zw); - - int side = sqrt(gl_VerticesIn); - - for (int j = 0; j < side; j++) - { - for (int k = 0; k < side; ++k) - { - vec3 pos = gl_PositionIn[(j * side) + k].xyz; - vec4 v = shadowMatrix[i] * vec4(pos, 1.0); - gl_Position = v; - to_vec = pos - light_position.xyz * depth; - EmitVertex(); - } - - EndPrimitive(); - } - - vec3 norms[3]; // Normals - vec3 lightdir3]; // Directions toward light - - vec4 v[4]; // Temporary vertices - - vec4 or_pos[3] = - { // Triangle oriented toward light source - gl_PositionIn[0], - gl_PositionIn[2], - gl_PositionIn[4] - }; - - // Compute normal at each vertex. - cross_products(n, 0, 2, 4); - - // Compute direction from vertices to light. - lightdir[0] = getLightDirection(lightpos, gl_PositionIn[0].xyz); - lightdir[1] = getLightDirection(lightpos, gl_PositionIn[2].xyz); - lightdir[2] = getLightDirection(lightpos, gl_PositionIn[4].xyz); - - // Check if the main triangle faces the light. - bool faces_light = true; - if (!(dot(ns[0],d[0]) > 0 - |dot(ns[1],d[1]) > 0 - |dot(ns[2],d[2]) > 0)) - { - // Flip vertex winding order in or_pos. - or_pos[1] = gl_PositionIn[4]; - or_pos[2] = gl_PositionIn[2]; - faces_light = false; - } - - // Near cap: simply render triangle. - emitTri(or_pos); - - // Far cap: extrude positions to infinity. - v[0] =vec4(lightpos.w * or_pos[0].xyz - lightpos.xyz,0); - v[1] =vec4(lightpos.w * or_pos[2].xyz - lightpos.xyz,0); - v[2] =vec4(lightpos.w * or_pos[1].xyz - lightpos.xyz,0); - - emitTri(v); - - // Loop over all edges and extrude if needed. - for ( int i=0; i<3; i++ ) - { - // Compute indices of neighbor triangle. - int v0 = i*2; - int nb = (i*2+1); - int v1 = (i*2+2) % 6; - cross_products(n, v0, nb, v1); - - // Compute direction to light, again as above. - d[0] =lightpos.xyz-lightpos.w*gl_PositionIn[v0].xyz; - d[1] =lightpos.xyz-lightpos.w*gl_PositionIn[nb].xyz; - d[2] =lightpos.xyz-lightpos.w*gl_PositionIn[v1].xyz; - - bool is_parallel = gl_PositionIn[nb].w < 1e-5; - - // Extrude the edge if it does not have a - // neighbor, or if it's a possible silhouette. - if (is_parallel || - ( faces_light != (dot(ns[0],d[0])>0 || - dot(ns[1],d[1])>0 || - dot(ns[2],d[2])>0) )) - { - // Make sure sides are oriented correctly. - int i0 = faces_light ? v0 : v1; - int i1 = faces_light ? v1 : v0; - - v[0] = gl_PositionIn[i0]; - v[1] = vec4(lightpos.w*gl_PositionIn[i0].xyz - lightpos.xyz, 0); - v[2] = gl_PositionIn[i1]; - v[3] = vec4(lightpos.w*gl_PositionIn[i1].xyz - lightpos.xyz, 0); - - emitQuad(v); - } - } -} - -void main() -{ - // Output - emitPrimitives(0); -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl new file mode 100644 index 0000000000..a04f611440 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl @@ -0,0 +1,122 @@ +/** + * @file fullbrightShinyF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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]*/ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +#ifndef HAS_DIFFUSE_LOOKUP +uniform sampler2D diffuseMap; +#endif + + +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; +VARYING vec3 vary_texcoord1; +VARYING vec3 vary_position; + +uniform samplerCube environmentMap; + +// render_hud_attachments() -> HUD objects set LLShaderMgr::NO_ATMO; used in LLDrawPoolAlpha::beginRenderPass() +uniform int no_atmo; + +vec3 fullbrightShinyAtmosTransport(vec3 light); +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten); +vec3 fullbrightScaleSoftClip(vec3 light); + +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); + +vec3 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); + +#ifdef HAS_REFLECTION_PROBES +// reflection probe interface +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv, + vec3 pos, vec3 norm, float glossiness, float envIntensity); +void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); +void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); +#endif + +// See: +// class1\deferred\fullbrightShinyF.glsl +// class1\lighting\lightFullbrightShinyF.glsl +void main() +{ +#ifdef HAS_DIFFUSE_LOOKUP + vec4 color = diffuseLookup(vary_texcoord0.xy); +#else + vec4 color = texture2D(diffuseMap, vary_texcoord0.xy); +#endif + + color.rgb *= vertex_color.rgb; + + // SL-9632 HUDs are affected by Atmosphere + if (no_atmo == 0) + { + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + vec3 pos = vary_position; + calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false); + + float env_intensity = vertex_color.a; +#ifndef HAS_REFLECTION_PROBES + vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb; + color.rgb = mix(color.rgb, envColor.rgb, env_intensity); +#else + vec3 ambenv; + vec3 glossenv; + vec3 legacyenv; + vec3 norm = normalize(vary_texcoord1.xyz); + vec4 spec = vec4(0,0,0,0); + sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, env_intensity); + legacyenv *= 1.5; // fudge brighter + applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity); +#endif + color.rgb = fullbrightAtmosTransportFrag(color.rgb, additive, atten); + color.rgb = fullbrightScaleSoftClip(color.rgb); + } + +/* + // NOTE: HUD objects will be full bright. Uncomment if you want "some" environment lighting effecting these HUD objects. + else + { + vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb; + float env_intensity = vertex_color.a; + color.rgb = mix(color.rgb, envColor.rgb, env_intensity); + } +*/ + + color.a = 1.0; + //color.rgb = linear_to_srgb(color.rgb); + + frag_color = color; +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl deleted file mode 100644 index 34d26cddea..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file class3/deferred/gatherSkyShF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_data[3]; -#else -#define frag_data gl_FragData -#endif - -VARYING vec2 vary_frag; - -uniform vec2 screen_res; -uniform sampler2D sh_input_r; -uniform sampler2D sh_input_g; -uniform sampler2D sh_input_b; - -void main() -{ - vec2 offset = vec2(2.0) / screen_res; - - vec4 r = vec4(0); - vec4 g = vec4(0); - vec4 b = vec4(0); - - vec2 tc = vary_frag * 2.0; - - r += texture2D(sh_input_r, tc + vec2(0, 0)); - r += texture2D(sh_input_r, tc + vec2(offset.x, 0)); - r += texture2D(sh_input_r, tc + vec2(0, offset.y)); - r += texture2D(sh_input_r, tc + vec2(offset.x, offset.y)); - r /= 4.0f; - - g += texture2D(sh_input_g, tc + vec2(0, 0)); - g += texture2D(sh_input_g, tc + vec2(offset.x, 0)); - g += texture2D(sh_input_g, tc + vec2(0, offset.y)); - g += texture2D(sh_input_g, tc + vec2(offset.x, offset.y)); - g /= 4.0f; - - b += texture2D(sh_input_b, tc + vec2(0, 0)); - b += texture2D(sh_input_b, tc + vec2(offset.x, 0)); - b += texture2D(sh_input_b, tc + vec2(0, offset.y)); - b += texture2D(sh_input_b, tc + vec2(offset.x, offset.y)); - b /= 4.0f; - - frag_data[0] = r; - frag_data[1] = g; - frag_data[2] = b; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl deleted file mode 100644 index 337c8a50fe..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file gatherSkyShV.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; - -VARYING vec2 vary_frag; -uniform vec2 screen_res; - -void main() -{ - // pass through untransformed fullscreen pos - float oo_divisor = screen_res.x / 64.0; - vec3 pos = (position.xyz * oo_divisor) + vec3(oo_divisor - 1, oo_divisor - 1, 0); - gl_Position = vec4(pos.xyz, 1.0); - vary_frag = texcoord0 * oo_divisor; -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl b/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl deleted file mode 100644 index d5d91c88f0..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @file class3/deferred/genSkyShF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_data[3]; -#else -#define frag_data gl_FragData -#endif - -VARYING vec2 vary_frag; - -uniform vec3 sun_dir; - -uniform sampler2D transmittance_texture; -uniform sampler3D scattering_texture; -uniform sampler3D single_mie_scattering_texture; -uniform sampler2D irradiance_texture; - -vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance); - -vec3 calcDirection(vec2 tc) -{ - float phi = tc.y * 2.0 * 3.14159265; - float cosTheta = sqrt(1.0 - tc.x); - float sinTheta = sqrt(1.0 - cosTheta * cosTheta); - return vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); -} - -// reverse mapping above to convert a hemisphere direction into phi/theta values -void getPhiAndThetaFromDirection(vec3 dir, out float phi, out float theta) -{ - float sin_theta; - float cos_theta; - cos_theta = dir.z; - theta = acos(cos_theta); - sin_theta = sin(theta); - phi = abs(sin_theta) > 0.0001 ? acos(dir.x / sin_theta) : 1.0; -} - -// reverse mapping above to convert a hemisphere direction into an SH texture sample pos -vec2 calcShUvFromDirection(vec3 dir) -{ - vec2 uv; - float phi; - float theta; - getPhiAndThetaFromDirection(dir, phi, theta); - uv.y = phi / 2.0 * 3.14159265; - uv.x = theta / 2.0 * 3.14159265; - return uv; -} - -void projectToL1(vec3 n, vec3 c, vec4 basis, out vec4 coeffs[3]) -{ - coeffs[0] = vec4(basis.x, n * basis.yzw * c.r); - coeffs[1] = vec4(basis.x, n * basis.yzw * c.g); - coeffs[2] = vec4(basis.x, n * basis.yzw * c.b); -} - -void main() -{ - float Y00 = sqrt(1.0 / 3.14159265) * 0.5; - float Y1x = sqrt(3.0 / 3.14159265) * 0.5; - float Y1y = Y1x; - float Y1z = Y1x; - - vec4 L1 = vec4(Y00, Y1x, Y1y, Y1z); - - vec3 view_direction = calcDirection(vary_frag); - vec3 sun_direction = normalize(sun_dir); - vec3 cam_pos = vec3(0, 0, 6360); - - vec3 transmittance; - vec3 radiance = GetSkyLuminance(cam_pos, view_direction, 0.0f, sun_direction, transmittance); - - vec3 color = vec3(1.0) - exp(-radiance * 0.0001); - - color = pow(color, vec3(1.0/2.2)); - - vec4 coeffs[3]; - coeffs[0] = vec4(0); - coeffs[1] = vec4(0); - coeffs[2] = vec4(0); - - projectToL1(view_direction, color.rgb, L1, coeffs); - - frag_data[0] = coeffs[0]; - frag_data[1] = coeffs[1]; - frag_data[2] = coeffs[2]; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl b/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl deleted file mode 100644 index 33c5667cae..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file class3/deferred/indirect.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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]*/ - -uniform sampler2D sh_input_r; -uniform sampler2D sh_input_g; -uniform sampler2D sh_input_b; - -vec3 GetIndirect(vec3 norm) -{ - vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265)); - vec4 l1r = texture2D(sh_input_r, vec2(0,0)); - vec4 l1g = texture2D(sh_input_g, vec2(0,0)); - vec4 l1b = texture2D(sh_input_b, vec2(0,0)); - vec3 indirect = vec3(dot(l1r, l1tap * vec4(1, norm.xyz)), - dot(l1g, l1tap * vec4(1, norm.xyz)), - dot(l1b, l1tap * vec4(1, norm.xyz))); - indirect = clamp(indirect, vec3(0), vec3(1.0)); - return indirect; -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl new file mode 100644 index 0000000000..7f8536cdab --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -0,0 +1,455 @@ +/** +* @file materialF.glsl +* +* $LicenseInfo:firstyear=2007&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2007, 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]*/ + +//class1/deferred/materialF.glsl + +// This shader is used for both writing opaque/masked content to the gbuffer and writing blended content to the framebuffer during the alpha pass. + +#define DIFFUSE_ALPHA_MODE_NONE 0 +#define DIFFUSE_ALPHA_MODE_BLEND 1 +#define DIFFUSE_ALPHA_MODE_MASK 2 +#define DIFFUSE_ALPHA_MODE_EMISSIVE 3 + +uniform float emissive_brightness; // fullbright flag, 1.0 == fullbright, 0.0 otherwise +uniform int sun_up_factor; + +#ifdef WATER_FOG +vec4 applyWaterFogView(vec3 pos, vec4 color); +#endif + +vec3 atmosFragLighting(vec3 l, vec3 additive, vec3 atten); +vec3 scaleSoftClipFrag(vec3 l); + +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten); +vec3 fullbrightScaleSoftClip(vec3 light); + +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); + +vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cs); + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +#ifdef HAS_SUN_SHADOW +float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); +#endif + +#ifdef HAS_REFLECTION_PROBES +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec3 pos, vec3 norm, float glossiness, float envIntensity); +void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); +void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); +#endif + +uniform samplerCube environmentMap; +uniform sampler2D lightFunc; + +// Inputs +uniform vec4 morphFactor; +uniform vec3 camPosLocal; +uniform mat3 env_mat; + +uniform vec3 sun_dir; +uniform vec3 moon_dir; +VARYING vec2 vary_fragcoord; + +VARYING vec3 vary_position; + +uniform mat4 proj_mat; +uniform mat4 inv_proj; +uniform vec2 screen_res; + +uniform vec4 light_position[8]; +uniform vec3 light_direction[8]; +uniform vec4 light_attenuation[8]; +uniform vec3 light_diffuse[8]; + +float getAmbientClamp(); + +vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, inout float glare, float ambiance) +{ + // SL-14895 inverted attenuation work-around + // This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct + // that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights() + // to recover the `adjusted_radius` value previously being sent as la. + float falloff_factor = (12.0 * fa) - 9.0; + float inverted_la = falloff_factor / la; + // Yes, it makes me want to cry as well. DJH + + vec3 col = vec3(0); + + //get light vector + vec3 lv = lp.xyz - v; + + //get distance + float dist = length(lv); + float da = 1.0; + + dist /= inverted_la; + + if (dist > 0.0 && inverted_la > 0.0) + { + //normalize light vector + lv = normalize(lv); + + //distance attenuation + float dist_atten = clamp(1.0 - (dist - 1.0*(1.0 - fa)) / fa, 0.0, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0f; + + if (dist_atten <= 0.0) + { + return col; + } + + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + + //angular attenuation + da *= dot(n, lv); + + float lit = 0.0f; + + float amb_da = ambiance; + if (da >= 0) + { + lit = max(da * dist_atten, 0.0); + col = lit * light_col * diffuse; + amb_da += (da*0.5 + 0.5) * ambiance; + } + amb_da += (da*da*0.5 + 0.5) * ambiance; + amb_da *= dist_atten; + amb_da = min(amb_da, 1.0f - lit); + + // SL-10969 need to see why these are blown out + //col.rgb += amb_da * light_col * diffuse; + + if (spec.a > 0.0) + { + //vec3 ref = dot(pos+lv, norm); + vec3 h = normalize(lv + npos); + float nh = dot(n, h); + float nv = dot(n, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4 + 0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); + + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt / (nh*da); + vec3 speccol = lit*scol*light_col.rgb*spec.rgb; + speccol = clamp(speccol, vec3(0), vec3(1)); + col += speccol; + + float cur_glare = max(speccol.r, speccol.g); + cur_glare = max(cur_glare, speccol.b); + glare = max(glare, speccol.r); + glare += max(cur_glare, 0.0); + } + } + } + + return max(col, vec3(0.0, 0.0, 0.0)); +} + +#else +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif +#endif + +uniform sampler2D diffuseMap; //always in sRGB space + +#ifdef HAS_NORMAL_MAP +uniform sampler2D bumpMap; +#endif + +#ifdef HAS_SPECULAR_MAP +uniform sampler2D specularMap; + +VARYING vec2 vary_texcoord2; +#endif + +uniform float env_intensity; +uniform vec4 specular_color; // specular color RGB and specular exponent (glossiness) in alpha + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK) +uniform float minimum_alpha; +#endif + +#ifdef HAS_NORMAL_MAP +VARYING vec3 vary_mat0; +VARYING vec3 vary_mat1; +VARYING vec3 vary_mat2; +VARYING vec2 vary_texcoord1; +#else +VARYING vec3 vary_normal; +#endif + +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +vec2 encode_normal(vec3 n); + +void main() +{ + vec2 pos_screen = vary_texcoord0.xy; + + vec4 diffcol = texture2D(diffuseMap, vary_texcoord0.xy); + diffcol.rgb *= vertex_color.rgb; + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK) + + // Comparing floats cast from 8-bit values, produces acne right at the 8-bit transition points + float bias = 0.001953125; // 1/512, or half an 8-bit quantization + if (diffcol.a < minimum_alpha-bias) + { + discard; + } +#endif + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + vec3 gamma_diff = diffcol.rgb; + diffcol.rgb = srgb_to_linear(diffcol.rgb); +#endif + +#ifdef HAS_SPECULAR_MAP + vec4 spec = texture2D(specularMap, vary_texcoord2.xy); + spec.rgb *= specular_color.rgb; +#else + vec4 spec = vec4(specular_color.rgb, 1.0); +#endif + +#ifdef HAS_NORMAL_MAP + vec4 norm = texture2D(bumpMap, vary_texcoord1.xy); + + norm.xyz = norm.xyz * 2 - 1; + + vec3 tnorm = vec3(dot(norm.xyz,vary_mat0), + dot(norm.xyz,vary_mat1), + dot(norm.xyz,vary_mat2)); +#else + vec4 norm = vec4(0,0,0,1.0); + vec3 tnorm = vary_normal; +#endif + + norm.xyz = normalize(tnorm.xyz); + + vec2 abnormal = encode_normal(norm.xyz); + + vec4 final_color = diffcol; + +#if (DIFFUSE_ALPHA_MODE != DIFFUSE_ALPHA_MODE_EMISSIVE) + final_color.a = emissive_brightness; +#else + final_color.a = max(final_color.a, emissive_brightness); +#endif + + vec4 final_specular = spec; + +#ifdef HAS_SPECULAR_MAP + vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity * spec.a, GBUFFER_FLAG_HAS_ATMOS); + final_specular.a = specular_color.a * norm.a; +#else + vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity, GBUFFER_FLAG_HAS_ATMOS); + final_specular.a = specular_color.a; +#endif + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + + //forward rendering, output just lit sRGBA + vec3 pos = vary_position; + + float shadow = 1.0f; + +#ifdef HAS_SUN_SHADOW + shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, pos_screen); +#endif + + spec = final_specular; + vec4 diffuse = final_color; + float envIntensity = final_normal.z; + + vec3 color = vec3(0,0,0); + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + + float bloom = 0.0; + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + + calcAtmosphericVars(pos.xyz, light_dir, 1.0, sunlit, amblit, additive, atten, false); + + // This call breaks the Mac GLSL compiler/linker for unknown reasons (17Mar2020) + // The call is either a no-op or a pure (pow) gamma adjustment, depending on GPU level + // TODO: determine if we want to re-apply the gamma adjustment, and if so understand & fix Mac breakage + //color = fullbrightScaleSoftClip(color); + + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + + //we're in sRGB space, so gamma correct this dot product so + // lighting from the sun stays sharp + float da = clamp(dot(normalize(norm.xyz), light_dir.xyz), 0.0, 1.0); + da = pow(da, 1.0 / 1.3); + vec3 sun_contrib = min(da, shadow) * sunlit; + +#ifdef HAS_REFLECTION_PROBES + vec3 ambenv; + vec3 glossenv; + vec3 legacyenv; + sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity); + amblit = max(ambenv, amblit); + color.rgb = amblit; +#else + + color = amblit; + + //darken ambient for normals perpendicular to light vector so surfaces in shadow + // and facing away from light still have some definition to them. + // do NOT gamma correct this dot product so ambient lighting stays soft + float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0 - ambient); + + color *= ambient; +#endif + + color += sun_contrib; + + color *= gamma_diff.rgb; + + float glare = 0.0; + + if (spec.a > 0.0) // specular reflection + { + float sa = dot(refnormpersp, sun_dir.xyz); + vec3 dumbshiny = sunlit * shadow * (texture2D(lightFunc, vec2(sa, spec.a)).r); + + // add the two types of shiny together + vec3 spec_contrib = dumbshiny * spec.rgb; + bloom = dot(spec_contrib, spec_contrib) / 6; + + glare = max(spec_contrib.r, spec_contrib.g); + glare = max(glare, spec_contrib.b); + + color += spec_contrib; + +#ifdef HAS_REFLECTION_PROBES + applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz); +#endif + } + + + color = mix(color.rgb, diffcol.rgb, diffuse.a); + +#ifdef HAS_REFLECTION_PROBES + if (envIntensity > 0.0) + { // add environmentmap + //fudge darker + legacyenv *= 0.5*diffuse.a+0.5; + + applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity); + } +#else + if (envIntensity > 0.0) + { + //add environmentmap + vec3 env_vec = env_mat * refnormpersp; + + vec3 reflected_color = textureCube(environmentMap, env_vec).rgb; + + color = mix(color, reflected_color, envIntensity); + + float cur_glare = max(reflected_color.r, reflected_color.g); + cur_glare = max(cur_glare, reflected_color.b); + cur_glare *= envIntensity*4.0; + glare += cur_glare; + } +#endif + + color = atmosFragLighting(color, additive, atten); + color = scaleSoftClipFrag(color); + + //convert to linear before adding local lights + color = srgb_to_linear(color); + + vec3 npos = normalize(-pos.xyz); + + vec3 light = vec3(0, 0, 0); + + final_specular.rgb = srgb_to_linear(final_specular.rgb); // SL-14035 + +#define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, final_specular, pos.xyz, norm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare, light_attenuation[i].w ); + + LIGHT_LOOP(1) + LIGHT_LOOP(2) + LIGHT_LOOP(3) + LIGHT_LOOP(4) + LIGHT_LOOP(5) + LIGHT_LOOP(6) + LIGHT_LOOP(7) + + color += light; + + glare = min(glare, 1.0); + float al = max(diffcol.a, glare)*vertex_color.a; + + //convert to srgb as this color is being written post gamma correction + color = linear_to_srgb(color); + +#ifdef WATER_FOG + vec4 temp = applyWaterFogView(pos, vec4(color, al)); + color = temp.rgb; + al = temp.a; +#endif + + frag_color = vec4(color, al); + +#else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer + + // deferred path // See: C++: addDeferredAttachment(), shader: softenLightF.glsl + frag_data[0] = final_color; // gbuffer is sRGB + frag_data[1] = final_specular; // XYZ = Specular color. W = Specular exponent. + frag_data[2] = final_normal; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog) +#endif +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl new file mode 100644 index 0000000000..71135786c3 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl @@ -0,0 +1,202 @@ +/** + * @file class3\deferred\multiPointLightF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +#extension GL_ARB_texture_rectangle : enable + +/*[EXTRA_CODE_HERE]*/ + +#define DEBUG_ANY_LIGHT_TYPE 0 // Output red light cone +#define DEBUG_PBR_LIGHT_TYPE 0 // Output PBR objects in red +#define DEBUG_LEG_LIGHT_TYPE 0 // Show Legacy objects in red +#define DEBUG_POINT_ZERO 0 // Output zero for spotlight + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect depthMap; +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl +uniform sampler2D noiseMap; +uniform sampler2D lightFunc; + +uniform vec3 env_mat[3]; +uniform float sun_wash; +uniform int light_count; +uniform vec4 light[LIGHT_COUNT]; // .w = size; see C++ fullscreen_lights.push_back() +uniform vec4 light_col[LIGHT_COUNT]; // .a = falloff + +uniform vec2 screen_res; +uniform float far_z; +uniform mat4 inv_proj; + +VARYING vec4 vary_fragcoord; + +vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh ); +vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRoughness, float specWeight, float vh, float nl, float nv, float nh ); +void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); +float calcLegacyDistanceAttenuation(float distance, float falloff); +vec3 getLightIntensityPoint(vec3 lightColor, float lightRange, float lightDistance); +vec4 getPosition(vec2 pos_screen); +vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec2 getScreenXY(vec4 clip); +void initMaterial( vec3 diffuse, vec3 packedORM, out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight ); +vec3 srgb_to_linear(vec3 c); + +// Util +vec3 hue_to_rgb(float hue); + +void main() +{ +#if defined(LOCAL_LIGHT_KILL) + discard; // Bail immediately +#else + vec3 final_color = vec3(0, 0, 0); + vec2 tc = getScreenXY(vary_fragcoord); + vec3 pos = getPosition(tc).xyz; + if (pos.z < far_z) + { + discard; + } + + float envIntensity; // not used for this shader + vec3 n; + vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + + vec4 spec = texture2DRect(specularRect, tc); + vec3 diffuse = texture2DRect(diffuseRect, tc).rgb; + + vec3 h, l, v = -normalize(pos); + float nh, nl, nv, vh, lightDist; + + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) + { + vec3 colorDiffuse = vec3(0); + vec3 colorSpec = vec3(0); + vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive. See: pbropaqueF.glsl + vec3 packedORM = texture2DRect(emissiveRect, tc).rgb; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl + + vec3 c_diff, reflect0, reflect90; + float alphaRough, specWeight; + initMaterial( diffuse, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight ); + + for (int light_idx = 0; light_idx < LIGHT_COUNT; ++light_idx) + { + vec3 lightColor = light_col[ light_idx ].rgb; // Already in linear, see pipeline.cpp: volume->getLightLinearColor(); + float falloff = light_col[ light_idx ].a; + float lightSize = light [ light_idx ].w; + vec3 lv =(light [ light_idx ].xyz - pos); + calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist); + + if (nl > 0.0) + { + float dist = lightDist / lightSize; + float dist_atten = calcLegacyDistanceAttenuation(dist, falloff); + + vec3 intensity = dist_atten * nl * lightColor; + colorDiffuse += intensity * BRDFLambertian (reflect0, reflect90, c_diff , specWeight, vh); + colorSpec += intensity * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh); + } + } + + #if DEBUG_PBR_LIGHT_TYPE + colorDiffuse = vec3(0.5,0,0); colorSpec = vec3(0); + #endif + final_color = colorDiffuse + colorSpec; + } + else + { + + float noise = texture2D(noiseMap, tc/128.0).b; + + // As of OSX 10.6.7 ATI Apple's crash when using a variable size loop + for (int i = 0; i < LIGHT_COUNT; ++i) + { + vec3 lv = light[i].xyz - pos; + float dist = length(lv); + dist /= light[i].w; + if (dist <= 1.0) + { + float nl = dot(n, lv); + if (nl > 0.0) + { + float lightDist; + calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist); + + float fa = light_col[i].a + 1.0; + float dist_atten = calcLegacyDistanceAttenuation(dist, fa); + dist_atten *= noise; + + float lit = nl * dist_atten; + + vec3 col = light_col[i].rgb * lit * diffuse; + + if (spec.a > 0.0) + { + lit = min(nl * 6.0, 1.0) * dist_atten; + float fres = pow(1 - vh, 5) * 0.4 + 0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * nl / vh)); + + if (nh > 0.0) + { + float scol = fres * texture2D(lightFunc, vec2(nh, spec.a)).r * gt / (nh * nl); + col += lit * scol * light_col[i].rgb * spec.rgb; + } + } + + final_color += col; + } + } + } + #if DEBUG_LEG_LIGHT_TYPE + final_color.rgb = vec3(0.5,0,0.0); + #endif + } + +#if DEBUG_POINT_ZERO + final_color = vec3(0); +#endif +#if DEBUG_ANY_LIGHT_TYPE + final_color = vec3(0.3333,0,0); +#endif + + frag_color.rgb = final_color; + frag_color.a = 0.0; +#endif // LOCAL_LIGHT_KILL + +#ifdef IS_AMD_CARD + // If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage + // away which leads to unfun crashes and artifacts. + vec4 dummy1 = light[0]; + vec4 dummy2 = light_col[0]; + vec4 dummy3 = light[LIGHT_COUNT - 1]; + vec4 dummy4 = light_col[LIGHT_COUNT - 1]; +#endif +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightV.glsl index bc5eb5181d..ad6a0fa752 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/sunLightV.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightV.glsl @@ -1,9 +1,9 @@ /** - * @file sunLightV.glsl + * @file class3\deferred\multiPointLightV.glsl * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2007, Linden Research, Inc. + * Copyright (C) 2022, 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 @@ -27,15 +27,13 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; -VARYING vec2 vary_fragcoord; - -uniform vec2 screen_res; +VARYING vec4 vary_fragcoord; void main() { //transform vertex vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - - vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; + vary_fragcoord = pos; + + gl_Position = pos; } diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl index 9d62b9d180..a9a2b8dcb4 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/multiSpotLightF.glsl @@ -1,9 +1,9 @@ /** - * @file multiSpotLightF.glsl + * @file class3\deferred\multiSpotLightF.glsl * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2007, Linden Research, Inc. + * Copyright (C) 2022, 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 @@ -28,6 +28,40 @@ /*[EXTRA_CODE_HERE]*/ +#define DEBUG_ANY_LIGHT_TYPE 0 // Output blue light cone +#define DEBUG_LEG_LIGHT_TYPE 0 // Show Legacy objects in blue +#define DEBUG_PBR_LIGHT_TYPE 0 // Ouput gray if PBR multiSpot lights object +#define DEBUG_PBR_SPOT 0 +#define DEBUG_PBR_SPOT_DIFFUSE 0 // PBR diffuse lit +#define DEBUG_PBR_SPOT_SPECULAR 0 // PBR spec lit + +#define DEBUG_LIGHT_FRUSTUM 0 // If projected light effects a surface +#define DEBUG_AMBIANCE_COLOR 0 // calculated ambiance color +#define DEBUG_AMBIANCE_AOE 0 // area of effect using inverse ambiance color +#define DEBUG_AMBIANCE_FINAL 0 // light color * ambiance color +#define DEBUG_NOISE 0 // monochrome noise +#define DEBUG_SHADOW 0 // Show inverted shadow +#define DEBUG_SPOT_DIFFUSE 0 // dot(n,l) * dist_atten +#define DEBUG_SPOT_NL 0 // monochome area effected by light +#define DEBUG_SPOT_SPEC_POS 0 +#define DEBUG_SPOT_REFLECTION 0 // color: pos reflected along n +#define DEBUG_SPOT_ZERO 0 // Output zero for spotlight + +#define DEBUG_PBR_LIGHT_H 0 // Half vector +#define DEBUG_PBR_LIHGT_L 0 // Light vector +#define DEBUG_PBR_LIGHT_NH 0 // colorized dot(n,h) +#define DEBUG_PBR_LIGHT_NL 0 // colorized dot(n,l) +#define DEBUG_PBR_LIGHT_NV 0 // colorized dot(n,v) +#define DEBUG_PBR_LIGHT_VH 0 // colorized dot(v,h) +#define DEBUG_PBR_LIGHT_DIFFUSE_COLOR 0 // non PBR spotlight +#define DEBUG_PBR_LIGHT_SPECULAR_COLOR 0 // non PBR spotlight +#define DEBUG_PBR_LIGHT_INTENSITY 0 // Light intensity +#define DEBUG_PBR_LIGHT_INTENSITY_NL 0 // Light intensity * dot(n,l) +#define DEBUG_PBR_LIGHT_BRDF_DIFFUSE 0 // like "fullbright" if no "nl" factor +#define DEBUG_PBR_LIGHT_BRDF_SPECULAR 0 +#define DEBUG_PBR_LIGHT_BRDF_FINAL 0 // BRDF Diffuse + BRDF Specular + + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else @@ -38,10 +72,11 @@ uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; +uniform sampler2DRect emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl uniform samplerCube environmentMap; uniform sampler2DRect lightMap; uniform sampler2D noiseMap; -uniform sampler2D projectionMap; +uniform sampler2D projectionMap; // rgba uniform sampler2D lightFunc; uniform mat4 proj_mat; //screen space to light space @@ -61,6 +96,7 @@ uniform float sun_wash; uniform int proj_shadow_idx; uniform float shadow_fade; +// Light params uniform vec3 center; uniform float size; uniform vec3 color; @@ -71,221 +107,327 @@ uniform vec2 screen_res; uniform mat4 inv_proj; -vec3 getNorm(vec2 pos_screen); - -vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) -{ - vec4 ret = texture2DLod(projectionMap, tc, lod); - - vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); - - float det = min(lod/(proj_lod*0.5), 1.0); - - float d = min(dist.x, dist.y); - - d *= min(1, d * (proj_lod - lod)); - - float edge = 0.25*det; - - ret *= clamp(d/edge, 0.0, 1.0); - - return ret; -} - -vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) -{ - vec4 ret = texture2DLod(projectionMap, tc, lod); - - vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); - - float det = min(lod/(proj_lod*0.5), 1.0); - - float d = min(dist.x, dist.y); - - float edge = 0.25*det; - - ret *= clamp(d/edge, 0.0, 1.0); - - return ret; -} - -vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) -{ - vec4 ret = texture2DLod(projectionMap, tc, lod); - - vec2 dist = tc-vec2(0.5); - - float d = dot(dist,dist); - - ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); - - return ret; -} - +vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh ); +vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRoughness, float specWeight, float vh, float nl, float nv, float nh ); +void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); +vec3 colorized_dot(float x); +bool clipProjectedLightVars(vec3 center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc ); +vec3 getLightIntensitySpot(vec3 lightColor, float lightRange, float lightDistance, vec3 v); +vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv); +vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv ); +vec3 getProjectedLightSpecularColor(vec3 pos, vec3 n); +vec2 getScreenXY(vec4 clip); +void initMaterial( vec3 diffuse, vec3 packedORM, out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight ); +vec3 srgb_to_linear(vec3 cs); +vec4 texture2DLodSpecular(vec2 tc, float lod); vec4 getPosition(vec2 pos_screen); -void main() +void main() { - vec4 frag = vary_fragcoord; - frag.xyz /= frag.w; - frag.xyz = frag.xyz*0.5+0.5; - frag.xy *= screen_res; - - vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = center.xyz-pos.xyz; - float dist = length(lv); - dist /= size; - if (dist > 1.0) +#if defined(LOCAL_LIGHT_KILL) + discard; +#else + vec3 final_color = vec3(0,0,0); + vec2 tc = getScreenXY(vary_fragcoord); + vec3 pos = getPosition(tc).xyz; + + vec3 lv; + vec4 proj_tc; + float dist, l_dist; + if (clipProjectedLightVars(center, pos, dist, l_dist, lv, proj_tc)) { discard; } - + float shadow = 1.0; if (proj_shadow_idx >= 0) { - vec4 shd = texture2DRect(lightMap, frag.xy); - shadow = (proj_shadow_idx == 0) ? shd.b : shd.a; + vec4 shd = texture2DRect(lightMap, tc); + shadow = (proj_shadow_idx==0)?shd.b:shd.a; shadow += shadow_fade; shadow = clamp(shadow, 0.0, 1.0); } - - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; - - float envIntensity = norm.z; - norm = getNorm(frag.xy); - - norm = normalize(norm); - float l_dist = -dot(lv, proj_n); - - vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); - if (proj_tc.z < 0.0) - { - discard; - } - - proj_tc.xyz /= proj_tc.w; - - float fa = (falloff*0.5)+1.0; - float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0); + float envIntensity; + vec3 n; + vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); + + float dist_atten = 1.0 - (dist + falloff)/(1.0 + falloff); dist_atten *= dist_atten; dist_atten *= 2.0; if (dist_atten <= 0.0) { discard; } - + lv = proj_origin-pos.xyz; - lv = normalize(lv); - float da = dot(norm, lv); + vec3 h, l, v = -normalize(pos); + float nh, nl, nv, vh, lightDist; + calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist); - vec3 col = vec3(0,0,0); - - vec3 diff_tex = srgb_to_linear(texture2DRect(diffuseRect, frag.xy).rgb); - - vec4 spec = texture2DRect(specularRect, frag.xy); + vec3 diffuse = texture2DRect(diffuseRect, tc).rgb; + vec4 spec = texture2DRect(specularRect, tc); + vec3 dlit = vec3(0, 0, 0); + vec3 slit = vec3(0, 0, 0); - vec3 dlit = vec3(0, 0, 0); + vec3 amb_rgb = vec3(0); - float noise = texture2D(noiseMap, frag.xy/128.0).b; - if (proj_tc.z > 0.0 && - proj_tc.x < 1.0 && - proj_tc.y < 1.0 && - proj_tc.x > 0.0 && - proj_tc.y > 0.0) + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { - float amb_da = proj_ambiance; - float lit = 0.0; + vec3 colorDiffuse = vec3(0); + vec3 colorSpec = vec3(0); + vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive. See: pbropaqueF.glsl + vec3 packedORM = texture2DRect(emissiveRect, tc).rgb; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl + float metal = packedORM.b; - if (da > 0.0) + // We need this additional test inside a light's frustum since a spotlight's ambiance can be applied + if (proj_tc.x > 0.0 && proj_tc.x < 1.0 + && proj_tc.y > 0.0 && proj_tc.y < 1.0) { - lit = da * dist_atten * noise; + float lit = 0.0; + float amb_da = 0.0; - float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); - float lod = diff * proj_lod; - - vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); - - dlit = color.rgb * plcol.rgb * plcol.a; - - col = dlit*lit*diff_tex*shadow; - amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; + if (nl > 0.0) + { + amb_da += (nl*0.5 + 0.5) * proj_ambiance; + lit = nl * dist_atten; + + vec3 c_diff, reflect0, reflect90; + float alphaRough, specWeight; + initMaterial( diffuse, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight ); + + dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy ); + slit = getProjectedLightSpecularColor( pos, n ); + + colorDiffuse = shadow * lit * (dlit*0.5 + BRDFLambertian ( reflect0, reflect90, c_diff , specWeight, vh )); + colorSpec = shadow * lit * (slit + BRDFSpecularGGX( reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh )); + + #if DEBUG_PBR_SPOT_DIFFUSE + colorDiffuse = dlit.rgb; colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SPOT_SPECULAR + colorDiffuse = vec3(0); colorSpec = slit.rgb; + #endif + #if DEBUG_PBR_SPOT + colorDiffuse = dlit; colorSpec = vec3(0); + colorDiffuse *= nl; + colorDiffuse *= shadow; + #endif + } + + amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy ); + colorDiffuse += diffuse.rgb * amb_rgb; + + #if DEBUG_AMBIANCE_FINAL + colorDiffuse = diffuse.rgb * amb_rgb; colorSpec = vec3(0); + #endif + #if DEBUG_LIGHT_FRUSTUM + colorDiffuse = vec3(0,1,0); colorSpec = vec3(0); + #endif + #if DEBUG_NOISE + float noise = texture2D(noiseMap, tc/128.0).b; + colorDiffuse = vec3(noise); colorSpec = vec3(0); + #endif } - - //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); - vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); - - amb_da += (da*da*0.5+0.5)*(1.0-shadow)*proj_ambiance; - - amb_da *= dist_atten * noise; - - amb_da = min(amb_da, 1.0-lit); - - col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; - } - - if (spec.a > 0.0) + #if DEBUG_PBR_LIGHT_TYPE + colorDiffuse = vec3(0.5,0,0); colorSpec = vec3(0); + #endif + + #if DEBUG_PBR_LIGHT_H + colorDiffuse = h*0.5 + 0.5; colorSpec = vec3(0); + #endif + #if DEBUG_PBR_LIHGT_L + colorDiffuse = l*0.5 + 0.5; colorSpec = vec3(0); + #endif + #if DEBUG_PBR_LIGHT_NH + colorDiffuse = colorized_dot(nh); colorSpec = vec3(0); + #endif + #if DEBUG_PBR_LIGHT_NL + colorDiffuse = colorized_dot(nl); colorSpec = vec3(0); + #endif + #if DEBUG_PBR_LIGHT_NV + colorDiffuse = colorized_dot(nv); colorSpec = vec3(0); + #endif + #if DEBUG_PBR_LIGHT_VH + colorDiffuse = colorized_dot(vh); colorSpec = vec3(0); + #endif + #if DEBUG_PBR_LIGHT_DIFFUSE_COLOR + colorDiffuse = dlit; + #endif + #if DEBUG_PBR_LIGHT_SPECULAR_COLOR + colorDiffuse = slit; + #endif + #if DEBUG_PBR_LIGHT_INTENSITY + colorDiffuse = getLightIntensitySpot( color, size, lightDist, v ); colorSpec = vec3(0); +// colorDiffuse = nl * dist_atten; + #endif + #if DEBUG_PBR_LIGHT_INTENSITY_NL + colorDiffuse = getLightIntensitySpot( color, size, lightDist, v ) * nl; colorSpec = vec3(0); + #endif + #if DEBUG_PBR_LIGHT_BRDF_DIFFUSE + vec3 c_diff, reflect0, reflect90; + float alphaRough, specWeight; + initMaterial( diffuse, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight ); + + colorDiffuse = BRDFLambertian ( reflect0, reflect90, c_diff , specWeight, vh ); + colorSpec = vec3(0); + #endif + #if DEBUG_PBR_LIGHT_BRDF_SPECULAR + vec3 c_diff, reflect0, reflect90; + float alphaRough, specWeight; + initMaterial( diffuse, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight ); + + colorDiffuse = vec3(0); + colorSpec = BRDFSpecularGGX( reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh ); + #endif + #if DEBUG_PBR_LIGHT_BRDF_FINAL + vec3 c_diff, reflect0, reflect90; + float alphaRough, specWeight; + initMaterial( diffuse, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight ); + colorDiffuse = nl * BRDFLambertian ( reflect0, reflect90, c_diff , specWeight, vh ); + colorSpec = nl * BRDFSpecularGGX( reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh ); + #endif + + final_color = colorDiffuse + colorSpec; + } + else { - vec3 npos = -normalize(pos); - dlit *= min(da*6.0, 1.0) * dist_atten; - - //vec3 ref = dot(pos+lv, norm); - vec3 h = normalize(lv+npos); - float nh = dot(norm, h); - float nv = dot(norm, npos); - float vh = dot(npos, h); - float sa = nh; - float fres = pow(1 - dot(h, npos), 5)*0.4+0.5; - - float gtdenom = 2 * nh; - float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); - - if (nh > 0.0) + float noise = texture2D(noiseMap, tc/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) { - float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); - col += dlit*scol*spec.rgb*shadow; - //col += spec.rgb; + float amb_da = 0; + float lit = 0.0; + + if (nl > 0.0) + { + lit = nl * dist_atten * noise; + + dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy ); + + final_color = dlit*lit*diffuse*shadow; + + // unshadowed for consistency between forward and deferred? + amb_da += (nl*0.5+0.5) /* * (1.0-shadow) */ * proj_ambiance; + } + + amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, noise, proj_tc.xy ); + final_color += diffuse.rgb * amb_rgb; +#if DEBUG_LEG_LIGHT_TYPE + final_color = vec3(0,0,0.5); +#endif } - } + + if (spec.a > 0.0) + { + dlit *= min(nl*6.0, 1.0) * dist_atten; - if (envIntensity > 0.0) - { - vec3 ref = reflect(normalize(pos), norm); + float fres = pow(1 - vh, 5)*0.4+0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * nl / vh)); + + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl); + vec3 speccol = dlit*scol*spec.rgb*shadow; + speccol = clamp(speccol, vec3(0), vec3(1)); + final_color += speccol; + } + } + + if (envIntensity > 0.0) + { + vec3 ref = reflect(normalize(pos), n); - //project from point pos in direction ref to plane proj_p, proj_n - vec3 pdelta = proj_p-pos; - float ds = dot(ref, proj_n); + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); - if (ds < 0.0) - { - vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; + if (ds < 0.0) + { + vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); - if (stc.z > 0.0) - { - stc /= stc.w; - - if (stc.x < 1.0 && - stc.y < 1.0 && - stc.x > 0.0 && - stc.y > 0.0) + if (stc.z > 0.0) { - col += color.rgb * texture2DLodSpecular(projectionMap, stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity; + stc /= stc.w; + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + final_color += color.rgb * texture2DLodSpecular(stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity; + } } } + #if DEBUG_SPOT_REFLECTION + final_color = ref; + #endif } + +#if DEBUG_LIGHT_FRUSTUM + if (proj_tc.x > 0.0 && proj_tc.x < 1.0 + && proj_tc.y > 0.0 && proj_tc.y < 1.0) + { + final_color = vec3(0,0,1); + } +#endif } - //not sure why, but this line prevents MATBUG-194 - col = max(col, vec3(0.0)); +#if DEBUG_AMBIANCE_AOE + if (proj_tc.x > 0.0 && proj_tc.x < 1.0 + && proj_tc.y > 0.0 && proj_tc.y < 1.0) + { + final_color = 1.0 - amb_rgb; + } +#endif +#if DEBUG_AMBIANCE_COLOR + if (proj_tc.x > 0.0 && proj_tc.x < 1.0 + && proj_tc.y > 0.0 && proj_tc.y < 1.0) + { + final_color = amb_rgb; + } +#endif +#if DEBUG_SHADOW + final_color = 1.0 - vec3(shadow); +#endif +#if DEBUG_SPOT_DIFFUSE + final_color = vec3(nl * dist_atten); +#endif +#if DEBUG_SPOT_NL + final_color =vec3(nl); +#endif +#if DEBUG_SPOT_SPEC_POS + vec3 ref = reflect(normalize(pos), n); + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + final_color = pos + ref * dot(pdelta, proj_n)/ds; +#endif +#if DEBUG_SPOT_REFLECTION + final_color = reflect(normalize(pos), n); +#endif +#if DEBUG_SPOT_ZERO + final_color = vec3(0,0,0); +#endif +#if DEBUG_ANY_LIGHT_TYPE + final_color = vec3(0,0,0.3333); +#endif - col = scaleDownLight(col); + //not sure why, but this line prevents MATBUG-194 + final_color = max(final_color, vec3(0.0)); - //output linear space color as gamma correction happens down stream - frag_color.rgb = col; + //output linear + frag_color.rgb = final_color; frag_color.a = 0.0; +#endif // LOCAL_LIGHT_KILL } diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl new file mode 100644 index 0000000000..6f39b0173b --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl @@ -0,0 +1,174 @@ +/** + * @file class3\deferred\pointLightF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +#extension GL_ARB_texture_rectangle : enable + +/*[EXTRA_CODE_HERE]*/ + +#define DEBUG_ANY_LIGHT_TYPE 0 // Output magenta light cone +#define DEBUG_LEG_LIGHT_TYPE 0 // Show Legacy objects in green +#define DEBUG_PBR_LIGHT_TYPE 0 // Show PBR objects in blue +#define DEBUG_POINT_ZERO 0 // Output zero for point light + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2DRect diffuseRect; +uniform sampler2DRect specularRect; +uniform sampler2DRect normalMap; +uniform sampler2DRect emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl +uniform sampler2D noiseMap; +uniform sampler2D lightFunc; +uniform sampler2DRect depthMap; + +uniform vec3 env_mat[3]; +uniform float sun_wash; + +// light params +uniform vec3 color; +uniform float falloff; +uniform float size; + +VARYING vec4 vary_fragcoord; +VARYING vec3 trans_center; + +uniform vec2 screen_res; + +uniform mat4 inv_proj; +uniform vec4 viewport; + +vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh ); +vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRoughness, float specWeight, float vh, float nl, float nv, float nh ); +void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); +float calcLegacyDistanceAttenuation(float distance, float falloff); +vec3 getLightIntensityPoint(vec3 lightColor, float lightRange, float lightDistance); +vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec4 getPosition(vec2 pos_screen); +vec2 getScreenXY(vec4 clip); +void initMaterial( vec3 diffuse, vec3 packedORM, out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight ); +vec3 srgb_to_linear(vec3 c); + +void main() +{ + vec3 final_color = vec3(0); + vec2 tc = getScreenXY(vary_fragcoord); + vec3 pos = getPosition(tc).xyz; + + float envIntensity; + vec3 n; + vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + + vec3 diffuse = texture2DRect(diffuseRect, tc).rgb; + vec4 spec = texture2DRect(specularRect, tc); + + // Common half vectors calcs + vec3 lv = trans_center.xyz-pos; + vec3 h, l, v = -normalize(pos); + float nh, nl, nv, vh, lightDist; + calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist); + + if (lightDist >= size) + { + discard; + } + float dist = lightDist / size; + float dist_atten = calcLegacyDistanceAttenuation(dist, falloff); + + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) + { + vec3 colorDiffuse = vec3(0); + vec3 colorSpec = vec3(0); + vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive. See: pbropaqueF.glsl + vec3 packedORM = texture2DRect(emissiveRect, tc).rgb; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl + float lightSize = size; + vec3 lightColor = color; // Already in linear, see pipeline.cpp: volume->getLightLinearColor(); + + vec3 c_diff, reflect0, reflect90; + float alphaRough, specWeight; + initMaterial( diffuse, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight ); + + if (nl > 0.0) + { + vec3 intensity = dist_atten * nl * lightColor; // Legacy attenuation + colorDiffuse += intensity * BRDFLambertian (reflect0, reflect90, c_diff , specWeight, vh); + colorSpec += intensity * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh); + } + +#if DEBUG_PBR_LIGHT_TYPE + colorDiffuse = vec3(0,0,0.5); colorSpec = vec3(0); +#endif + final_color = colorDiffuse + colorSpec; + } + else + { + if (nl < 0.0) + { + discard; + } + + float noise = texture2D(noiseMap, tc/128.0).b; + float lit = nl * dist_atten * noise; + + final_color = color.rgb*lit*diffuse; + + if (spec.a > 0.0) + { + lit = min(nl*6.0, 1.0) * dist_atten; + + float sa = nh; + float fres = pow(1 - vh, 5) * 0.4+0.5; + float gtdenom = 2 * nh; + float gt = max(0,(min(gtdenom * nv / vh, gtdenom * nl / vh))); + + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl); + final_color += lit*scol*color.rgb*spec.rgb; + } + } + + if (dot(final_color, final_color) <= 0.0) + { + discard; + } + +#if DEBUG_LEG_LIGHT_TYPE + final_color.rgb = vec3(0,0.25,0); +#endif + } + +#if DEBUG_POINT_ZERO + final_color = vec3(0); +#endif +#if DEBUG_ANY_LIGHT_TYPE + final_color = vec3(0.25,0,0.25); +#endif + + frag_color.rgb = final_color; + frag_color.a = 0.0; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointLightV.glsl index db8c75fb8a..d42c8f6cf6 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/pointLightV.glsl @@ -1,9 +1,9 @@ /** - * @file class3/deferred/shadowCubeV.glsl + * @file class3\deferred\pointLightV.glsl * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2007, Linden Research, Inc. + * Copyright (C) 2022, 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 @@ -24,27 +24,22 @@ */ uniform mat4 modelview_projection_matrix; +uniform mat4 modelview_matrix; ATTRIBUTE vec3 position; -#if !defined(DEPTH_CLAMP) -VARYING vec4 post_pos; -#endif +uniform vec3 center; +uniform float size; -uniform vec3 box_center; -uniform vec3 box_size; +VARYING vec4 vary_fragcoord; +VARYING vec3 trans_center; void main() { //transform vertex - vec3 p = position*box_size+box_center; - vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0); - -#if !defined(DEPTH_CLAMP) - post_pos = pos; - - gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); -#else + vec3 p = position*size+center; + vec4 pos = modelview_projection_matrix * vec4(p.xyz, 1.0); + vary_fragcoord = pos; + trans_center = (modelview_matrix*vec4(center.xyz, 1.0)).xyz; gl_Position = pos; -#endif } diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl deleted file mode 100644 index ca9ce3a2e1..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file pointShadowBlur.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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 samplerCube cube_map; - -in vec3 to_vec; - -out vec4 fragColor; - -void main() -{ - vec4 vcol = texture(cube_map, to_vec); - fragColor = vec4(vcol.rgb, 1.0); -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl new file mode 100644 index 0000000000..83348077d7 --- /dev/null +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -0,0 +1,566 @@ +/** + * @file class3/deferred/reflectionProbeF.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +#extension GL_ARB_shader_texture_lod : enable + +#define FLT_MAX 3.402823466e+38 + +#define REFMAP_COUNT 256 +#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider + +uniform samplerCubeArray reflectionProbes; +uniform samplerCubeArray irradianceProbes; + +layout (std140, binding = 1) uniform ReflectionProbes +{ + // list of OBBs for user override probes + // box is a set of 3 planes outward facing planes and the depth of the box along that plane + // for each box refBox[i]... + /// box[0..2] - plane 0 .. 2 in [A,B,C,D] notation + // box[3][0..2] - plane thickness + mat4 refBox[REFMAP_COUNT]; + // list of bounding spheres for reflection probes sorted by distance to camera (closest first) + vec4 refSphere[REFMAP_COUNT]; + // extra parameters (currently only .x used for probe ambiance) + vec4 refParams[REFMAP_COUNT]; + // index of cube map in reflectionProbes for a corresponding reflection probe + // e.g. cube map channel of refSphere[2] is stored in refIndex[2] + // refIndex.x - cubemap channel in reflectionProbes + // refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index) + // refIndex.z - number of neighbors + // refIndex.w - priority, if negative, this probe has a box influence + ivec4 refIndex[REFMAP_COUNT]; + + // neighbor list data (refSphere indices, not cubemap array layer) + ivec4 refNeighbor[1024]; + + // number of reflection probes present in refSphere + int refmapCount; +}; + +// Inputs +uniform mat3 env_mat; + +// list of probeIndexes shader will actually use after "getRefIndex" is called +// (stores refIndex/refSphere indices, NOT rerflectionProbes layer) +int probeIndex[REF_SAMPLE_COUNT]; + +// number of probes stored in probeIndex +int probeInfluences = 0; + +bool isAbove(vec3 pos, vec4 plane) +{ + return (dot(plane.xyz, pos) + plane.w) > 0; +} + +int max_priority = 0; + +// return true if probe at index i influences position pos +bool shouldSampleProbe(int i, vec3 pos) +{ + if (refIndex[i].w < 0) + { + vec4 v = refBox[i] * vec4(pos, 1.0); + if (abs(v.x) > 1 || + abs(v.y) > 1 || + abs(v.z) > 1) + { + return false; + } + + max_priority = max(max_priority, -refIndex[i].w); + } + else + { + vec3 delta = pos.xyz - refSphere[i].xyz; + float d = dot(delta, delta); + float r2 = refSphere[i].w; + r2 *= r2; + + if (d > r2) + { //outside bounding sphere + return false; + } + + max_priority = max(max_priority, refIndex[i].w); + } + + return true; +} + +// call before sampleRef +// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT +// overall algorithm -- +void preProbeSample(vec3 pos) +{ + // TODO: make some sort of structure that reduces the number of distance checks + + for (int i = 0; i < refmapCount; ++i) + { + // found an influencing probe + if (shouldSampleProbe(i, pos)) + { + probeIndex[probeInfluences] = i; + ++probeInfluences; + + int neighborIdx = refIndex[i].y; + if (neighborIdx != -1) + { + int neighborCount = min(refIndex[i].z, REF_SAMPLE_COUNT-1); + + int count = 0; + while (count < neighborCount) + { + // check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index) + + int idx = refNeighbor[neighborIdx].x; + if (shouldSampleProbe(idx, pos)) + { + probeIndex[probeInfluences++] = idx; + if (probeInfluences == REF_SAMPLE_COUNT) + { + return; + } + } + count++; + if (count == neighborCount) + { + return; + } + + idx = refNeighbor[neighborIdx].y; + if (shouldSampleProbe(idx, pos)) + { + probeIndex[probeInfluences++] = idx; + if (probeInfluences == REF_SAMPLE_COUNT) + { + return; + } + } + count++; + if (count == neighborCount) + { + return; + } + + idx = refNeighbor[neighborIdx].z; + if (shouldSampleProbe(idx, pos)) + { + probeIndex[probeInfluences++] = idx; + if (probeInfluences == REF_SAMPLE_COUNT) + { + return; + } + } + count++; + if (count == neighborCount) + { + return; + } + + idx = refNeighbor[neighborIdx].w; + if (shouldSampleProbe(idx, pos)) + { + probeIndex[probeInfluences++] = idx; + if (probeInfluences == REF_SAMPLE_COUNT) + { + return; + } + } + count++; + if (count == neighborCount) + { + return; + } + + ++neighborIdx; + } + + return; + } + } + } +} + +// from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection + +// original reference implementation: +/* +bool intersect(const Ray &ray) const +{ + float t0, t1; // solutions for t if the ray intersects +#if 0 + // geometric solution + Vec3f L = center - orig; + float tca = L.dotProduct(dir); + // if (tca < 0) return false; + float d2 = L.dotProduct(L) - tca * tca; + if (d2 > radius2) return false; + float thc = sqrt(radius2 - d2); + t0 = tca - thc; + t1 = tca + thc; +#else + // analytic solution + Vec3f L = orig - center; + float a = dir.dotProduct(dir); + float b = 2 * dir.dotProduct(L); + float c = L.dotProduct(L) - radius2; + if (!solveQuadratic(a, b, c, t0, t1)) return false; +#endif + if (t0 > t1) std::swap(t0, t1); + + if (t0 < 0) { + t0 = t1; // if t0 is negative, let's use t1 instead + if (t0 < 0) return false; // both t0 and t1 are negative + } + + t = t0; + + return true; +} */ + +// adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere +vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2) +{ + float t0, t1; // solutions for t if the ray intersects + + vec3 L = center - origin; + float tca = dot(L,dir); + + float d2 = dot(L,L) - tca * tca; + + float thc = sqrt(radius2 - d2); + t0 = tca - thc; + t1 = tca + thc; + + vec3 v = origin + dir * t1; + return v; +} + +// from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ +/* +vec3 DirectionWS = normalize(PositionWS - CameraWS); +vec3 ReflDirectionWS = reflect(DirectionWS, NormalWS); + +// Intersection with OBB convertto unit box space +// Transform in local unit parallax cube space (scaled and rotated) +vec3 RayLS = MulMatrix( float(3x3)WorldToLocal, ReflDirectionWS); +vec3 PositionLS = MulMatrix( WorldToLocal, PositionWS); + +vec3 Unitary = vec3(1.0f, 1.0f, 1.0f); +vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS; +vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS; +vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect); +float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z)); + +// Use Distance in WS directly to recover intersection +vec3 IntersectPositionWS = PositionWS + ReflDirectionWS * Distance; +vec3 ReflDirectionWS = IntersectPositionWS - CubemapPositionWS; + +return texCUBE(envMap, ReflDirectionWS); +*/ + +// get point of intersection with given probe's box influence volume +// origin - ray origin in clip space +// dir - ray direction in clip space +// i - probe index in refBox/refSphere +vec3 boxIntersect(vec3 origin, vec3 dir, int i) +{ + // Intersection with OBB convertto unit box space + // Transform in local unit parallax cube space (scaled and rotated) + mat4 clipToLocal = refBox[i]; + + vec3 RayLS = mat3(clipToLocal) * dir; + vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz; + + vec3 Unitary = vec3(1.0f, 1.0f, 1.0f); + vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS; + vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS; + vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect); + float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z)); + + // Use Distance in CS directly to recover intersection + vec3 IntersectPositionCS = origin + dir * Distance; + + return IntersectPositionCS; +} + + + +// Tap a reflection probe +// pos - position of pixel +// dir - pixel normal +// lod - which mip to bias towards (lower is higher res, sharper reflections) +// c - center of probe +// r2 - radius of probe squared +// i - index of probe +// vi - point at which reflection vector struck the influence volume, in clip space +vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i) +{ + //lod = max(lod, 1); + // parallax adjustment + + vec3 v; + if (refIndex[i].w < 0) + { + v = boxIntersect(pos, dir, i); + } + else + { + v = sphereIntersect(pos, dir, c, r2); + } + + v -= c; + v = env_mat * v; + { + return textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), lod).rgb; + } +} + +// Tap an irradiance map +// pos - position of pixel +// dir - pixel normal +// c - center of probe +// r2 - radius of probe squared +// i - index of probe +// vi - point at which reflection vector struck the influence volume, in clip space +vec3 tapIrradianceMap(vec3 pos, vec3 dir, vec3 c, float r2, int i) +{ + //lod = max(lod, 1); + // parallax adjustment + + vec3 v; + if (refIndex[i].w < 0) + { + v = boxIntersect(pos, dir, i); + } + else + { + v = sphereIntersect(pos, dir, c, r2); + } + + v -= c; + v = env_mat * v; + { + return texture(irradianceProbes, vec4(v.xyz, refIndex[i].x)).rgb * refParams[i].x; + } +} + +vec3 sampleProbes(vec3 pos, vec3 dir, float lod, float minweight) +{ + float wsum = 0.0; + vec3 col = vec3(0,0,0); + float vd2 = dot(pos,pos); // view distance squared + + for (int idx = 0; idx < probeInfluences; ++idx) + { + int i = probeIndex[idx]; + if (abs(refIndex[i].w) < max_priority) + { + continue; + } + float r = refSphere[i].w; // radius of sphere volume + float p = float(abs(refIndex[i].w)); // priority + + float rr = r*r; // radius squred + float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down) + vec3 delta = pos.xyz-refSphere[i].xyz; + float d2 = dot(delta,delta); + float r2 = r1*r1; + + { + vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i); + + float w = 1.0/d2; + + float atten = 1.0-max(d2-r2, 0.0)/(rr-r2); + w *= atten; + //w *= p; // boost weight based on priority + col += refcol*w; + + wsum += w; + } + } + + if (probeInfluences <= 1) + { //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera + for (int idx = 0; idx < 8; ++idx) + { + if (refIndex[idx].w < 0) + { // don't fallback to box probes, they are *very* specific + continue; + } + int i = idx; + vec3 delta = pos.xyz-refSphere[i].xyz; + float d2 = dot(delta,delta); + + { + vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i); + + float w = 1.0/d2; + w *= w; + col += refcol*w; + wsum += w; + } + } + } + + if (wsum > 0.0) + { + col *= 1.0/wsum; + } + + return col; +} + +vec3 sampleProbeAmbient(vec3 pos, vec3 dir) +{ + // modified copy/paste of sampleProbes follows, will likely diverge from sampleProbes further + // as irradiance map mixing is tuned independently of radiance map mixing + float wsum = 0.0; + vec3 col = vec3(0,0,0); + float vd2 = dot(pos,pos); // view distance squared + + float minweight = 1.0; + + for (int idx = 0; idx < probeInfluences; ++idx) + { + int i = probeIndex[idx]; + if (abs(refIndex[i].w) < max_priority) + { + continue; + } + float r = refSphere[i].w; // radius of sphere volume + float p = float(abs(refIndex[i].w)); // priority + + float rr = r*r; // radius squred + float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down) + vec3 delta = pos.xyz-refSphere[i].xyz; + float d2 = dot(delta,delta); + float r2 = r1*r1; + + { + vec3 refcol = tapIrradianceMap(pos, dir, refSphere[i].xyz, rr, i); + + float w = 1.0/d2; + + float atten = 1.0-max(d2-r2, 0.0)/(rr-r2); + w *= atten; + //w *= p; // boost weight based on priority + col += refcol*w; + + wsum += w; + } + } + + if (probeInfluences <= 1) + { //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera + for (int idx = 0; idx < 8; ++idx) + { + if (refIndex[idx].w < 0) + { // don't fallback to box probes, they are *very* specific + continue; + } + int i = idx; + vec3 delta = pos.xyz-refSphere[i].xyz; + float d2 = dot(delta,delta); + + { + vec3 refcol = tapIrradianceMap(pos, dir, refSphere[i].xyz, d2, i); + + float w = 1.0/d2; + w *= w; + col += refcol*w; + wsum += w; + } + } + } + + if (wsum > 0.0) + { + col *= 1.0/wsum; + } + + return col; +} + +// brighten a color so that at least one component is 1 +vec3 brighten(vec3 c) +{ + float m = max(max(c.r, c.g), c.b); + + if (m == 0) + { + return vec3(1,1,1); + } + + return c * 1.0/m; +} + + +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec3 pos, vec3 norm, float glossiness, float envIntensity) +{ + // TODO - don't hard code lods + float reflection_lods = 8; + preProbeSample(pos); + + vec3 refnormpersp = reflect(pos.xyz, norm.xyz); + + ambenv = sampleProbeAmbient(pos, norm); + + if (glossiness > 0.0) + { + float lod = (1.0-glossiness)*reflection_lods; + glossenv = sampleProbes(pos, normalize(refnormpersp), lod, 1.f); + } + + if (envIntensity > 0.0) + { + legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0, 1.f); + } +} + +void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm) +{ + glossenv *= 0.35; // fudge darker + float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz); + float minf = spec.a * 0.1; + fresnel = fresnel * (1.0-minf) + minf; + glossenv *= spec.rgb*min(fresnel, 1.0); + color.rgb += glossenv; +} + + void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity) + { + vec3 reflected_color = legacyenv; //*0.5; //fudge darker + vec3 lookAt = normalize(pos); + float fresnel = 1.0+dot(lookAt, norm.xyz); + fresnel *= fresnel; + fresnel = min(fresnel+envIntensity, 1.0); + reflected_color *= (envIntensity*fresnel)*brighten(spec.rgb); + color = mix(color.rgb, reflected_color, envIntensity); + } + diff --git a/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl deleted file mode 100644 index c8991f7a18..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file class3/deferred/shVisF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -#ifdef DEFINE_GL_FRAGCOLOR - out vec4 frag_color; -#else - #define frag_color gl_FragColor -#endif - -///////////////////////////////////////////////////////////////////////// -// Fragment shader for L1 SH debug rendering -///////////////////////////////////////////////////////////////////////// - -uniform sampler2D sh_input_r; -uniform sampler2D sh_input_g; -uniform sampler2D sh_input_b; - -uniform mat3 inv_modelviewprojection; - -VARYING vec4 vary_pos; - -void main(void) -{ - vec2 coord = vary_pos.xy + vec2(0.5,0.5); - - coord.x *= (1.6/0.9); - - if (dot(coord, coord) > 0.25) - { - discard; - } - - vec4 n = vec4(coord*2.0, 0.0, 1); - //n.y = -n.y; - n.z = sqrt(max(1.0-n.x*n.x-n.y*n.y, 0.0)); - //n.xyz = inv_modelviewprojection * n.xyz; - - vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265)); - vec4 l1r = texture2D(sh_input_r, vec2(0,0)); - vec4 l1g = texture2D(sh_input_g, vec2(0,0)); - vec4 l1b = texture2D(sh_input_b, vec2(0,0)); - vec3 indirect = vec3( - dot(l1r, l1tap * n), - dot(l1g, l1tap * n), - dot(l1b, l1tap * n)); - - //indirect = pow(indirect, vec3(0.45)); - indirect *= 3.0; - - frag_color = vec4(indirect, 1.0); -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl deleted file mode 100644 index af1461c297..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file shadowAlphaMaskV.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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 texture_matrix0; -uniform mat4 modelview_projection_matrix; -uniform float shadow_target_width; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; - -#if !defined(DEPTH_CLAMP) -VARYING float pos_zd2; -#endif - -VARYING float target_pos_x; -VARYING vec4 pos; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - -void passTextureIndex(); - -void main() -{ - //transform vertex - vec4 pre_pos = vec4(position.xyz, 1.0); - vec4 pos = modelview_projection_matrix * pre_pos; - target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; - - pos_w = pos.w; - -#if !defined(DEPTH_CLAMP) - pos_zd2 = pos.z * 0.5; - - gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); -#else - gl_Position = pos; -#endif - - passTextureIndex(); - - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vertex_color = diffuse_color; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl deleted file mode 100644 index 50f1ffd626..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file class3/deferred/shadowAlphaMaskF.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2D diffuseMap; - -#if !defined(DEPTH_CLAMP) -VARYING float pos_zd2; -#endif - -VARYING float pos_w; - -VARYING float target_pos_x; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - -vec4 getPosition(vec2 screen_coord); -vec4 computeMoments(float depth, float a); - -void main() -{ - vec4 pos = getPosition(vary_texcoord0.xy); - - float alpha = diffuseLookup(vary_texcoord0.xy).a * vertex_color.a; - - if (alpha < 0.05) // treat as totally transparent - { - discard; - } - - if (alpha < 0.88) // treat as semi-transparent - { - if (fract(0.5*floor(target_pos_x / pos_w )) < 0.25) - { - discard; - } - } - - frag_color = computeMoments(length(pos.xyz), alpha); - -#if !defined(DEPTH_CLAMP) - gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0); -#endif - -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl deleted file mode 100644 index 6a646f5e9e..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file class3/deferred/shadowAlphaMaskV.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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 texture_matrix0; -uniform mat4 modelview_projection_matrix; -uniform float shadow_target_width; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; - -#if !defined(DEPTH_CLAMP) -VARYING float pos_zd2; -#endif - -VARYING vec4 pos; -VARYING float target_pos_x; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - -void passTextureIndex(); - -void main() -{ - //transform vertex - vec4 pre_pos = vec4(position.xyz, 1.0); - - pos = modelview_projection_matrix * pre_pos; - - target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; - -#if !defined(DEPTH_CLAMP) - pos_zd2 = pos.z * 0.5; - - gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); -#else - gl_Position = pos; -#endif - - passTextureIndex(); - - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - - vertex_color = diffuse_color; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl deleted file mode 100644 index 3350267130..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file class3/deferred/shadowF.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2D diffuseMap; - -#if !defined(DEPTH_CLAMP) -VARYING float pos_zd2; -#endif - -VARYING vec4 pos; -VARYING float target_pos_x; - -vec4 computeMoments(float depth, float a); - -void main() -{ - frag_color = computeMoments(length(pos), 1.0); -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl deleted file mode 100644 index 2f69a353e8..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl +++ /dev/null @@ -1,157 +0,0 @@ -/** - * @file class3/deferred/shadowUtil.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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 sampler2D shadowMap0; -uniform sampler2D shadowMap1; -uniform sampler2D shadowMap2; -uniform sampler2D shadowMap3; -uniform sampler2D shadowMap4; -uniform sampler2D shadowMap5; - -uniform vec3 sun_dir; -uniform vec3 moon_dir; -uniform vec2 shadow_res; -uniform vec2 proj_shadow_res; -uniform mat4 shadow_matrix[6]; -uniform vec4 shadow_clip; -uniform float shadow_bias; - -uniform float spot_shadow_bias; -uniform float spot_shadow_offset; - -float getDepth(vec2 screenpos); -vec3 getNorm(vec2 screenpos); -vec4 getPosition(vec2 pos_screen); - -float ReduceLightBleeding(float p_max, float Amount) -{ - return smoothstep(Amount, 1, p_max); -} - -float ChebyshevUpperBound(vec2 m, float t, float min_v, float Amount) -{ - float p = (t <= m.x) ? 1.0 : 0.0; - - float v = m.y - (m.x*m.x); - v = max(v, min_v); - - float d = t - m.x; - - float p_max = v / (v + d*d); - - p_max = ReduceLightBleeding(p_max, Amount); - - return max(p, p_max); -} - -vec4 computeMoments(float depth, float a) -{ - float m1 = depth; - float dx = dFdx(depth); - float dy = dFdy(depth); - float m2 = m1*m1 + 0.25 * a * (dx*dx + dy*dy); - return vec4(m1, m2, a, max(dx, dy)); -} - -float vsmDirectionalSample(vec4 stc, float depth, sampler2D shadowMap, mat4 shadowMatrix) -{ - vec4 lpos = shadowMatrix * stc; - vec4 moments = texture2D(shadowMap, lpos.xy); - return ChebyshevUpperBound(moments.rg, depth - shadow_bias * 256.0f, 0.125, 0.9); -} - -float vsmSpotSample(vec4 stc, float depth, sampler2D shadowMap, mat4 shadowMatrix) -{ - vec4 lpos = shadowMatrix * stc; - vec4 moments = texture2D(shadowMap, lpos.xy); - lpos.xyz /= lpos.w; - lpos.xy *= 0.5; - lpos.xy += 0.5; - return ChebyshevUpperBound(moments.rg, depth - spot_shadow_bias * 16.0f, 0.125, 0.9); -} - -#if VSM_POINT_SHADOWS -float vsmPointSample(float lightDistance, vec3 lightDirection, samplerCube shadow_cube_map) -{ - vec4 moments = textureCube(shadow_cube_map, light_direction); - return ChebyshevUpperBound(moments.rg, light_distance, 0.01, 0.25); -} -#endif - -float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen) -{ - if (pos.z < -shadow_clip.w) - { - discard; - } - - float depth = getDepth(pos_screen); - - vec4 spos = vec4(pos,1.0); - vec4 near_split = shadow_clip*-0.75; - vec4 far_split = shadow_clip*-1.25; - - float shadow = 0.0f; - float weight = 1.0; - - if (spos.z < near_split.z) - { - shadow += vsmDirectionalSample(spos, depth, shadowMap3, shadow_matrix[3]); - weight += 1.0f; - } - if (spos.z < near_split.y) - { - shadow += vsmDirectionalSample(spos, depth, shadowMap2, shadow_matrix[2]); - weight += 1.0f; - } - if (spos.z < near_split.x) - { - shadow += vsmDirectionalSample(spos, depth, shadowMap1, shadow_matrix[1]); - weight += 1.0f; - } - if (spos.z > far_split.x) - { - shadow += vsmDirectionalSample(spos, depth, shadowMap0, shadow_matrix[0]); - weight += 1.0f; - } - - shadow /= weight; - - return shadow; -} - -float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen) -{ - if (pos.z < -shadow_clip.w) - { - discard; - } - - float depth = getDepth(pos_screen); - - pos += norm * spot_shadow_offset; - return vsmSpotSample(vec4(pos, 1.0), depth, (index == 0) ? shadowMap4 : shadowMap5, shadow_matrix[4 + index]); -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl deleted file mode 100644 index 6577fe0ecf..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file class3/deferred/shadowV.glsl - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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; -uniform float shadow_target_width; -uniform mat4 texture_matrix0; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; - -#if !defined(DEPTH_CLAMP) -VARYING float pos_zd2; -#endif - -VARYING vec4 pos; -VARYING float target_pos_x; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - -void passTextureIndex(); - -void main() -{ - //transform vertex - vec4 pre_pos = vec4(position.xyz, 1.0); - - pos = modelview_projection_matrix * pre_pos; - - target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; - -#if !defined(DEPTH_CLAMP) - pos_zd2 = pos.z * 0.5; - - gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); -#else - gl_Position = pos; -#endif - - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/skyF.glsl deleted file mode 100644 index a0b082ed7c..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/skyF.glsl +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file class3/deferred/skyF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_data[3]; -#else -#define frag_data gl_FragData -#endif - -VARYING vec2 vary_frag; - -uniform vec3 camPosLocal; -uniform vec3 sun_dir; -uniform float sun_size; -uniform float far_z; -uniform mat4 inv_proj; -uniform mat4 inv_modelview; - -uniform sampler2D transmittance_texture; -uniform sampler3D scattering_texture; -uniform sampler3D single_mie_scattering_texture; -uniform sampler2D irradiance_texture; -uniform sampler2D rainbow_map; -uniform sampler2D halo_map; - -uniform float moisture_level; -uniform float droplet_radius; -uniform float ice_level; - -vec3 GetSolarLuminance(); -vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance); -vec3 GetSkyLuminanceToPoint(vec3 camPos, vec3 pos, float shadow_length, vec3 dir, out vec3 transmittance); - -vec3 ColorFromRadiance(vec3 radiance); -vec3 rainbow(float d) -{ - // d is the dot product of view and sun directions, so ranging -1.0..1.0 - // 'interesting' values of d are the range -0.75..-0.825, when view is nearly opposite of sun vec - // Rainbox texture mode is GL_REPEAT, so tc of -.75 is equiv to 0.25, -0.825 equiv to 0.175. - - // SL-13629 Rainbow texture has colors within the correct .175...250 range, but order is inverted. - // Rather than replace the texture, we mirror and translate the y tc to keep the colors within the - // interesting range, but in reversed order: i.e. d = (1 - d) - 1.575 - d = clamp(-0.575 - d, 0.0, 1.0); - - // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible. - // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate - // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857 - float interior_coord = max(0.0, d - 0.25) * 4.2857; - d = clamp(d, 0.0, 0.25) + interior_coord; - - float rad = (droplet_radius - 5.0f) / 1024.0f; - return pow(texture2D(rainbow_map, vec2(rad, d)).rgb, vec3(1.8)) * moisture_level; -} - -vec3 halo22(float d) -{ - float v = sqrt(max(0, 1 - (d*d))); - return texture2D(halo_map, vec2(0, v)).rgb * ice_level; -} - -void main() -{ - vec3 pos = vec3((vary_frag * 2.0) - vec2(1.0, 1.0f), 1.0); - vec4 view_pos = (inv_proj * vec4(pos, 1.0f)); - - view_pos /= view_pos.w; - - vec3 view_ray = (inv_modelview * vec4(view_pos.xyz, 0.0f)).xyz + camPosLocal; - - vec3 view_direction = normalize(view_ray); - vec3 sun_direction = normalize(sun_dir); - vec3 earth_center = vec3(0, 0, -6360.0f); - vec3 camPos = (camPosLocal / 1000.0f) - earth_center; - - vec3 transmittance; - vec3 radiance_sun = GetSkyLuminance(camPos, view_direction, 0.0f, sun_direction, transmittance); - vec3 solar_luminance = GetSolarLuminance(); - - // If the view ray intersects the Sun, add the Sun radiance. - float s = dot(view_direction, sun_direction); - - // cheesy solar disc... - if (s >= (sun_size * 0.999)) - { - radiance_sun += pow(smoothstep(0.0, 1.3, (s - (sun_size * 0.9))), 2.0) * solar_luminance * transmittance; - } - s = smoothstep(0.9, 1.0, s) * 16.0f; - - vec3 color = ColorFromRadiance(radiance_sun); - - float optic_d = dot(view_direction, sun_direction); - vec3 halo_22 = halo22(optic_d); - - color.rgb += rainbow(optic_d) * optic_d; - color.rgb += halo_22; - - color = pow(color, vec3(1.0/2.2)); - - frag_data[0] = vec4(color, 1.0 + s); - frag_data[1] = vec4(0.0); - frag_data[2] = vec4(0.0, 1.0, 0.0, 1.0); -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class3/deferred/skyV.glsl deleted file mode 100644 index 2eb222ada4..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/skyV.glsl +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file class3/deferred/skyV.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; - -VARYING vec2 vary_frag; - -void main() -{ - // pass through untransformed fullscreen pos at back of frustum for proper sky depth testing - gl_Position = vec4(position.xy, 1.0f, 1.0); - vary_frag = texcoord0; -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 7ed9e7b4fc..998ebf8836 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -1,31 +1,129 @@ -/** +/** * @file class3/deferred/softenLightF.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, 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$ */ - + +#define PBR_USE_ATMOS 1 +#define PBR_USE_IBL 1 +#define PBR_USE_SUN 1 + +#define DEBUG_PBR_LIGHT_TYPE 0 // Output no global light to make it easier to see pointLight and spotLight +#define DEBUG_PBR_PACKORM0 0 // Rough=0, Metal=0 +#define DEBUG_PBR_PACKORM1 0 // Rough=1, Metal=1 +#define DEBUG_PBR_TANGENT1 1 // Tangent = 1,0,0 +#define DEBUG_PBR_VERT2CAM1 0 // vertex2camera = 0,0,1 +#define DEBUG_PBR_SPECLIGHT051 0 // Force specLigh to be 0,0.5,1 + +// Pass input through "as is" +#define DEBUG_PBR_DIFFUSE_MAP 0 // Output: use diffuse in G-Buffer +#define DEBUG_PBR_EMISSIVE 0 // Output: Emissive +#define DEBUG_PBR_METAL 0 // Output: grayscale Metal map +#define DEBUG_PBR_NORMAL_MAP 0 // Output: Normal -- also need to set DEBUG_NORMAL_MAP in pbropaqueF +#define DEBUG_PBR_OCCLUSION 0 // Output: grayscale Occlusion map +#define DEBUG_PBR_ORM 0 // Output: Packed Occlusion Roughness Metal +#define DEBUG_PBR_ROUGH_PERCEPTUAL 0 // Output: grayscale Perceptual Roughness map +#define DEBUG_PBR_ROUGH_ALPHA 0 // Output: grayscale Alpha Roughness + +#define DEBUG_PBR_TANGENT 0 // Output: Tangent +#define DEBUG_PBR_BITANGENT 0 // Output: Bitangent +#define DEBUG_PBR_DOT_BV 0 // Output: graysacle dot(Bitangent,Vertex2Camera) +#define DEBUG_PBR_DOT_TV 0 // Output: grayscale dot(Tangent ,Vertex2Camera) + +// IBL Spec +#define DEBUG_PBR_NORMAL 0 // Output: passed in normal +#define DEBUG_PBR_V2C_RAW 0 // Output: vertex2camera +#define DEBUG_PBR_DOT_NV 0 // Output: grayscale dot(Normal ,Vertex2Camera) +#define DEBUG_PBR_BRDF_UV 0 // Output: red green BRDF UV (GGX input) +#define DEBUG_PBR_BRDF_SCALE_BIAS 0 // Output: red green BRDF Scale Bias (GGX output) +#define DEBUG_PBR_BRDF_SCALE_ONLY 0 // Output: grayscale BRDF Scale +#define DEBUG_PBR_BRDF_BIAS_ONLY 0 // Output: grayscale BRDER Bias +#define DEBUG_PBR_FRESNEL 0 // Output: roughness dependent fresnel +#define DEBUG_PBR_KSPEC 0 // Output: K spec +#define DEBUG_PBR_REFLECTION_DIR 0 // Output: reflection dir +#define DEBUG_PBR_SPEC_IBL 0 // Output: IBL specularity +#define DEBUG_PBR_SPEC_LEGACY 0 // Output: legacyenv +#define DEBUG_PBR_SPEC_REFLECTION 0 // Output: environment reflection +#define DEBUG_PBR_FSS_ESS_GGX 0 // Output: FssEssGGX +#define DEBUG_PBR_SPEC 0 // Output: Final spec + +// IBL Diffuse +#define DEBUG_PBR_DIFFUSE_C 0 // Output: diffuse non metal mix +#define DEBUG_PBR_IRRADIANCE_RAW 0 // Output: Diffuse Irradiance pre-mix +#define DEBUG_PBR_IRRADIANCE 0 // Output: Diffuse Irradiance, NOTE: SSAO is factored in +#define DEBUG_PBR_FSS_ESS_LAMBERT 0 // Output: FssEssLambert +#define DEBUG_PBR_EMS 0 // Output: Ems = (1 - BRDF Scale + BRDF Bias) +#define DEBUG_PBR_AVG 0 // Output: Avg +#define DEBUG_PBR_FMS_EMS 0 // Output: FmsEms +#define DEBUG_PBR_DIFFUSE_K 0 // Output: diffuse FssEssLambert + FmsEms +#define DEBUG_PBR_DIFFUSE_PRE_AO 0 // Output: diffuse pre AO +#define DEBUG_PBR_DIFFUSE 0 // Output: diffuse post AO + +// Atmospheric Lighting +#define DEBUG_PBR_AMBENV 0 // Output: ambient environment +#define DEBUG_PBR_AMBOCC 0 // Output: ambient occlusion +#define DEBUG_PBR_DA_RAW 0 // Output: da pre pow() +#define DEBUG_PBR_DA_POW 0 // Output: da post pow() +#define DEBUG_PBR_SUN_LIT 0 // Ouput: sunlit +#define DEBUG_PBR_SUN_CONTRIB 0 // Output: sun_contrib +#define DEBUG_PBR_SKY_ADDITIVE 0 // Output: additive +#define DEBUG_PBR_SKY_ATTEN 0 // Output: greyscale atten.r + +// Sun +#define DEBUG_PBR_SUN_FULL_BRIGHT 0 // Sunlit color = <1,1,1> +#define DEBUG_PBR_SUN_OUT_DIFFUSE 0 // Final sun diffuse : intensity * nl * diffuse +#define DEBUG_PBR_SUN_OUT_SPECULAR 0 // Final sun specular: intensity * nl * specular +#define DEBUG_PBR_SUN_LAMBERT 0 // BRDF Diffuse: Lambertian Diffuse color +#define DEBUG_PBR_SUN_LAMBERT_NL 0 // BRDF Diffuse: nl * Lambertian Diffuse color +#define DEBUG_PBR_SUN_H 0 // Half Vector +#define DEBUG_PBR_SUN_L 0 // Light Vector +#define DEBUG_PBR_SUN_V 0 // Surface to Light Vector +#define DEBUG_PBR_SUN_NH 0 // dot(n,h) +#define DEBUG_PBR_SUN_NL 0 // dot(n,l) +#define DEBUG_PBR_SUN_NV 0 // dot(n,v) +#define DEBUG_PBR_SUN_VH 0 // dot(v,h) +#define DEBUG_PBR_SUN_REFLECT0 0 // reflect0 only +#define DEBUG_PBR_SUN_SPEC_FRESNEL 0 // Fresnel +#define DEBUG_PBR_SUN_SPEC_D 0 // D(h) +#define DEBUG_PBR_SUN_SPEC_V 0 // V(l,v,h) +#define DEBUG_PBR_SUN_SPEC_DF 0 // D() * F() +#define DEBUG_PBR_SUN_SPEC_DV 0 // D() * V() +#define DEBUG_PBR_SUN_SPEC_FV 0 // F() * V() +#define DEBUG_PBR_SUN_SPEC_DFV 0 // D() * F() * V() +#define DEBUG_PBR_SUN_SPEC_NL_DFV 0 // nl * D() * F() * V() + +#define DEBUG_PBR_IOR 0 // Output: grayscale IOR +#define DEBUG_PBR_REFLECT0_BASE 0 // Output: black reflect0 default from ior +#define DEBUG_PBR_REFLECT0_MIX 0 // Output: diffuse reflect0 calculated from ior +#define DEBUG_PBR_REFLECTANCE 0 // Output: diffuse reflectance -- NOT USED +#define DEBUG_PBR_SPEC_WEIGHT 0 // Output: specWeight +#define DEBUG_PBR_V2C_REMAP 0 // Output: vertex2camera (remap [-1,1] -> [0,1]) #extension GL_ARB_texture_rectangle : enable +#extension GL_ARB_shader_texture_lod : enable + +#define FLT_MAX 3.402823466e+38 -/*[EXTRA_CODE_HERE]*/ +#define REFMAP_COUNT 256 +#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -36,142 +134,577 @@ out vec4 frag_color; uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect normalMap; +uniform sampler2DRect emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl + +#if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO) uniform sampler2DRect lightMap; +#endif + uniform sampler2DRect depthMap; uniform sampler2D lightFunc; -uniform samplerCube environmentMap; uniform float blur_size; uniform float blur_fidelity; // Inputs -uniform vec4 morphFactor; -uniform vec3 camPosLocal; -uniform float cloud_shadow; -uniform float max_y; -uniform vec4 glow; uniform mat3 env_mat; -uniform vec4 shadow_clip; uniform vec3 sun_dir; +uniform vec3 moon_dir; +uniform int sun_up_factor; VARYING vec2 vary_fragcoord; uniform mat4 inv_proj; -uniform mat4 inv_modelview; - uniform vec2 screen_res; -uniform sampler2D transmittance_texture; -uniform sampler3D scattering_texture; -uniform sampler3D single_mie_scattering_texture; -uniform sampler2D irradiance_texture; - -uniform sampler2D sh_input_r; -uniform sampler2D sh_input_g; -uniform sampler2D sh_input_b; - -vec3 GetSunAndSkyIrradiance(vec3 camPos, vec3 norm, vec3 dir, out vec3 sky_irradiance); -vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance); -vec3 GetSkyLuminanceToPoint(vec3 camPos, vec3 pos, float shadow_length, vec3 dir, out vec3 transmittance); - -vec3 ColorFromRadiance(vec3 radiance); -vec4 getPositionWithDepth(vec2 pos_screen, float depth); -vec4 getPosition(vec2 pos_screen); vec3 getNorm(vec2 pos_screen); +vec4 getPositionWithDepth(vec2 pos_screen, float depth); + +vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh ); +vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRoughness, float specWeight, float vh, float nl, float nv, float nh ); +void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao); +float calcF0(float ior); +void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); + +float getAmbientClamp(); +vec2 getGGX( vec2 brdfPoint ); +void initMaterial( vec3 diffuse, vec3 packedORM, + out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight ); +vec3 atmosFragLighting(vec3 l, vec3 additive, vec3 atten); +vec3 scaleSoftClipFrag(vec3 l); +vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten); +vec3 fullbrightScaleSoftClip(vec3 light); + +// reflection probe interface +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv, + vec3 pos, vec3 norm, float glossiness, float envIntensity); +void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm); +void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity); + +vec3 linear_to_srgb(vec3 c); +vec3 srgb_to_linear(vec3 c); + +// Debug Utils +vec3 BRDFDiffuse(vec3 color); +vec3 colorize_dot(float x); +vec3 fresnelSchlick( vec3 reflect0, vec3 reflect90, float vh); +float D_GGX( float nh, float alphaRough ); +float V_GGX( float nl, float nv, float alphaRough ); #ifdef WATER_FOG vec4 applyWaterFogView(vec3 pos, vec4 color); #endif -void main() +uniform vec3 view_dir; // PBR + +void main() { - vec2 tc = vary_fragcoord.xy; - float depth = texture2DRect(depthMap, tc.xy).r; - vec3 pos = getPositionWithDepth(tc, depth).xyz; - vec4 norm = texture2DRect(normalMap, tc); + vec2 tc = vary_fragcoord.xy; + float depth = texture2DRect(depthMap, tc.xy).r; + vec4 pos = getPositionWithDepth(tc, depth); + vec4 norm = texture2DRect(normalMap, tc); float envIntensity = norm.z; - norm.xyz = getNorm(tc); + norm.xyz = getNorm(tc); + + vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; + float da = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0); +#if DEBUG_PBR_DA_RAW + float debug_da = da; +#endif + float light_gamma = 1.0 / 1.3; + da = pow(da, light_gamma); - float da = max(dot(norm.xyz, sun_dir.xyz), 0.0); + vec4 diffuse = texture2DRect(diffuseRect, tc); + vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); // NOTE: PBR sRGB Emissive - vec4 diffuse = texture2DRect(diffuseRect, tc); // sRGB - diffuse.rgb = srgb_to_linear(diffuse.rgb); +#if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO) + vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; + scol_ambocc = pow(scol_ambocc, vec2(light_gamma)); + float scol = max(scol_ambocc.r, diffuse.a); + float ambocc = scol_ambocc.g; +#else + float scol = 1.0; + float ambocc = 1.0; +#endif - vec3 col; + vec3 color = vec3(0); float bloom = 0.0; + + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + + calcAtmosphericVars(pos.xyz, light_dir, ambocc, sunlit, amblit, additive, atten, true); + + //vec3 amb_vec = env_mat * norm.xyz; + + vec3 ambenv; + vec3 glossenv; + vec3 legacyenv; + + bool hasPBR = GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR); + if (hasPBR) { - vec3 camPos = (camPosLocal / 1000.0f) + vec3(0, 0, 6360.0f); + // 5.22.2. material.pbrMetallicRoughness.baseColorTexture + // The first three components (RGB) MUST be encoded with the sRGB transfer function. + // + // 5.19.7. material.emissiveTexture + // This texture contains RGB components encoded with the sRGB transfer function. + // + // 5.22.5. material.pbrMetallicRoughness.metallicRoughnessTexture + // These values MUST be encoded with a linear transfer function. + + vec3 colorDiffuse = vec3(0); + vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive. See: pbropaqueF.glsl + vec3 colorSpec = vec3(0); +// vec3 colorClearCoat = vec3(0); +// vec3 colorSheen = vec3(0); +// vec3 colorTransmission = vec3(0); + + vec3 packedORM = texture2DRect(emissiveRect, tc).rgb; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl +#if DEBUG_PBR_PACK_ORM0 + packedORM = vec3(0,0,0); +#endif +#if DEBUG_PBR_PACK_ORM1 + packedORM = vec3(1,1,1); +#endif + float IOR = 1.5; // default Index Of Refraction 1.5 (dielectrics) +#if DEBUG_PBR_REFLECT0_BASE + vec3 debug_reflect0 = vec3(calcF0(IOR)); +#endif + float ao = packedORM.r; + float metal = packedORM.b; + vec3 v = -normalize(pos.xyz); +#if DEBUG_PBR_VERT2CAM1 + v = vec3(0,0,1); +#endif + vec3 n = norm.xyz; +// vec3 t = texture2DRect(tangentMap, tc).rgb; +#if DEBUG_PBR_TANGENT1 + vec3 t = vec3(1,0,0); +#endif + vec3 b = cross( n,t); + vec3 reflectVN = normalize(reflect(-v,n)); + + vec3 h, l; + float nh, nl, nv, vh, lightDist; + calcHalfVectors(light_dir, n, v, h, l, nh, nl, nv, vh, lightDist); + + float tv = clamp(dot(t,v),0,1); + float bv = clamp(dot(b,v),0,1); + + // Reference: getMetallicRoughnessInfo + vec3 base = linear_to_srgb(diffuse.rgb); + float perceptualRough = max(packedORM.g, 0.1); + vec3 c_diff, reflect0, reflect90; + float alphaRough, specWeight; + initMaterial( base, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight ); +#if DEBUG_PBR_REFLECTANCE + float reflectance = max( max( reflect0.r, reflect0.g ), reflect0.b ); +#endif - vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); - - vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; + // Common to RadianceGGX and RadianceLambertian + vec2 brdfPoint = clamp(vec2(nv, perceptualRough), vec2(0,0), vec2(1,1)); + vec2 vScaleBias = getGGX( brdfPoint); // Environment BRDF: scale and bias applied to reflect0 + vec3 fresnelR = max(vec3(1.0 - perceptualRough), reflect0) - reflect0; // roughness dependent fresnel + vec3 kSpec = reflect0 + fresnelR*pow(1.0 - nv, 5.0); + + // Reference: getIBLRadianceGGX + // https://forum.substance3d.com/index.php?topic=3243.0 + // Glossiness + // This map is the inverse of the roughness map. + vec3 irradiance = vec3(0); + vec3 specLight = vec3(0); + float gloss = 1.0 - perceptualRough; + sampleReflectionProbes(irradiance, specLight, legacyenv, pos.xyz, norm.xyz, gloss, 0.0); +#if DEBUG_PBR_IRRADIANCE_RAW + vec3 debug_irradiance = irradiance; +#endif + irradiance = max(amblit,irradiance) * ambocc; + specLight = srgb_to_linear(specLight); +#if DEBUG_PBR_SPECLIGHT051 + specLight = vec3(0,0.5,1.0); + irradiance = specLight; +#endif +#if HAS_IBL + kSpec = mix( kSpec, iridescenceFresnel, iridescenceFactor); +#endif + vec3 FssEssGGX = kSpec*vScaleBias.x + vScaleBias.y; +#if DEBUG_PBR_SPEC_IBL + vec3 debug_color_spec = specWeight * specLight * FssEssGGX; +#endif +#if PBR_USE_IBL + colorSpec += specWeight * specLight * FssEssGGX; +#endif - float scol = max(scol_ambocc.r, diffuse.a); + // Reference: getIBLRadianceLambertian + vec3 FssEssLambert = specWeight * kSpec * vScaleBias.x + vScaleBias.y; // NOTE: Very similar to FssEssRadiance but with extra specWeight term + float Ems = 1.0 - (vScaleBias.x + vScaleBias.y); + vec3 avg = specWeight * (reflect0 + (1.0 - reflect0) / 21.0); + vec3 AvgEms = avg * Ems; + vec3 FmsEms = AvgEms * FssEssLambert / (1.0 - AvgEms); + vec3 kDiffuse = c_diff * (1.0 - FssEssLambert + FmsEms); +#if PBR_USE_IBL + colorDiffuse += (FmsEms + kDiffuse) * irradiance; +#endif + #if DEBUG_PBR_DIFFUSE_PRE_AO + vec3 debug_diffuse = colorDiffuse; + #endif - float ambocc = scol_ambocc.g; + colorDiffuse *= ao; // Occlusion -- NOTE: pbropaque will need occlusion_strength pre-multiplied into spec.r + colorSpec *= ao; - vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265)); - vec4 l1r = texture2D(sh_input_r, vec2(0,0)); - vec4 l1g = texture2D(sh_input_g, vec2(0,0)); - vec4 l1b = texture2D(sh_input_b, vec2(0,0)); + // Add in sun/moon reflection + if (nl > 0.0 || nv > 0.0) + { + float scale = 4.9; + vec3 sunColor = srgb_to_linear(sunlit * scale); // NOTE: Midday should have strong sunlight +#if DEBUG_PBR_SUN_FULL_BRIGHT + sunColor = vec3(1); +#endif + // scol = sun shadow + vec3 intensity = ambocc * sunColor * nl * scol; + vec3 sunDiffuse = base * intensity * BRDFLambertian (reflect0, reflect90, c_diff , specWeight, vh); + vec3 sunSpec = intensity * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh); + bloom = dot(sunSpec, sunSpec) / (scale * scale * scale); + + #if DEBUG_PBR_SUN_SPEC_FRESNEL + colorDiffuse = vec3(0); + colorSpec = fresnelSchlick( reflect0, reflect90, vh ); + bloom = 0; + #endif + #if DEBUG_PBR_SUN_SPEC_D + colorDiffuse = vec3(0); + colorSpec = vec3(D_GGX( nh, alphaRough )); + bloom = 0; + #endif + #if DEBUG_PBR_SUN_SPEC_V + colorDiffuse = vec3(0); + colorSpec = vec3(V_GGX( nl, nv, alphaRough )); + bloom = 0; + #endif + #if DEBUG_PBR_SUN_SPEC_DF + colorDiffuse = vec3(0); + colorSpec = fresnelSchlick( reflect0, reflect90, vh ); + colorSpec *= D_GGX( nh, alphaRough ); + bloom = 0; + #endif + #if DEBUG_PBR_SUN_SPEC_DV + colorDiffuse = vec3(0); + colorSpec = vec3(D_GGX( nh, alphaRough )); + colorSpec *= vec3(V_GGX( nl, nv, alphaRough )); + bloom = 0; + #endif + #if DEBUG_PBR_SUN_SPEC_FV + colorDiffuse = vec3(0); + colorSpec = fresnelSchlick( reflect0, reflect90, vh ); + colorSpec *= V_GGX( nl, nv, alphaRough ); + bloom = 0; + #endif + #if DEBUG_PBR_SUN_SPEC_DFV + colorDiffuse = vec3(0); + colorSpec = fresnelSchlick( reflect0, reflect90, vh ); + colorSpec *= D_GGX( nh, alphaRough ); + colorSpec *= V_GGX( nl, nv, alphaRough ); + bloom = 0; + #endif + #if DEBUG_PBR_SUN_SPEC_NL_DFV + colorDiffuse = vec3(0); + colorSpec = nl * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh); + #endif + #if DEBUG_PBR_SUN_FINAL + colorDiffuse = nl * BRDFLambertian (reflect0, reflect90, c_diff , specWeight, vh); + colorSpec = nl * BRDFSpecularGGX(reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh); + #endif + + #if DEBUG_PBR_SUN_OUT_DIFFUSE + colorDiffuse = linear_to_srgb(sunDiffuse); + colorSpec = vec3(0); + bloom = 0.0; + #endif + #if DEBUG_PBR_SUN_OUT_SPECULAR + colorDiffuse = linear_to_srgb(sunSpec); + colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SUN_REFLECT0 + colorDiffuse = reflect0; + colorSpec = vec3(0); + #endif + +#if PBR_USE_SUN + colorDiffuse += sunDiffuse; + colorSpec += sunSpec; +#endif + } - vec3 indirect = vec3(dot(l1r, l1tap * vec4(1, norm.xyz)), - dot(l1g, l1tap * vec4(1, norm.xyz)), - dot(l1b, l1tap * vec4(1, norm.xyz))); +#if DEBUG_PBR_SUN_LAMBERT + colorDiffuse = BRDFLambertian (reflect0, reflect90, c_diff , specWeight, vh); + colorSpec = vec3(0); + bloom = 0; +#endif +#if DEBUG_PBR_SUN_LAMBERT_NL + colorDiffuse = nl * BRDFLambertian (reflect0, reflect90, c_diff , specWeight, vh); + colorSpec = vec3(0); + bloom = 0; +#endif - indirect = clamp(indirect, vec3(0), vec3(1.0)); + #if DEBUG_PBR_SUN_H + colorDiffuse = h*0.5 + 0.5; colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SUN_L + colorDiffuse = l*0.5 + 0.5; colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SUN_V + colorDiffuse = v*0.5 + 0.5; colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SUN_NH + colorDiffuse = colorize_dot(nh); colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SUN_NL + colorDiffuse = colorize_dot(nl); colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SUN_NV + colorDiffuse = colorize_dot(nv); colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SUN_VH + colorDiffuse = colorize_dot(vh); colorSpec = vec3(0); + #endif + + color.rgb = colorDiffuse + colorEmissive + colorSpec; + +#if PBR_USE_ATMOS + color = linear_to_srgb(color); + color *= atten.r; + color += 2.0*additive; + color = scaleSoftClipFrag(color); + color = srgb_to_linear(color); +#endif // PBR_USE_ATMOS + + #if DEBUG_PBR_DIFFUSE + color.rgb = colorDiffuse; + #endif + #if DEBUG_PBR_EMISSIVE + color.rgb = colorEmissive; + #endif + #if DEBUG_PBR_METAL + color.rgb = vec3(metal); + #endif + #if DEBUG_PBR_NORMAL_MAP + color.rgb = diffuse.rgb; + #endif + #if DEBUG_PBR_OCCLUSION + color.rgb = vec3(ao); + #endif + #if DEBUG_PBR_ORM + color.rgb = packedORM; + #endif + #if DEBUG_PBR_ROUGH_PERCEPTUAL + color.rgb = vec3(perceptualRough); + #endif + #if DEBUG_PBR_ROUGH_ALPHA + color.rgb = vec3(alphaRough); + #endif + + #if DEBUG_PBR_NORMAL + color.rgb = norm.xyz*0.5 + vec3(0.5); + color.rgb = srgb_to_linear(color.rgb); + #endif + #if DEBUG_PBR_TANGENT + color.rgb = t; + #endif + #if DEBUG_PBR_BITANGENT + color.rgb = b; + #endif + #if DEBUG_PBR_DOT_NV + color.rgb = vec3(nv); + #endif + #if DEBUG_PBR_DOT_TV + color.rgb = vec3(tv); + #endif + #if DEBUG_PBR_DOT_BV + color.rgb = vec3(bv); + #endif + + #if DEBUG_PBR_AVG + color.rgb = avg; + #endif + #if DEBUG_PBR_BRDF_UV + color.rgb = vec3(brdfPoint,0.0); + color.rgb = linear_to_srgb(color.rgb); + #endif + #if DEBUG_PBR_BRDF_SCALE_BIAS + color.rgb = vec3(vScaleBias,0.0); + #endif + #if DEBUG_PBR_DIFFUSE_C + color.rgb = c_diff; + #endif + #if DEBUG_PBR_BRDF_SCALE_ONLY + color.rgb = vec3(vScaleBias.x); + #endif + #if DEBUG_PBR_BRDF_BIAS_ONLY + color.rgb = vec3(vScaleBias.y); + #endif + #if DEBUG_PBR_DIFFUSE_K + color.rgb = kDiffuse; + #endif + #if DEBUG_PBR_DIFFUSE_MAP + color.rgb = diffuse.rgb; + #endif + #if DEBUG_PBR_DIFFUSE_PRE_AO + color.rgb = debug_diffuse; + #endif + #if DEBUG_PBR_EMS + color.rgb = vec3(Ems); + #endif + #if DEBUG_PBR_EMS_AVG + color.rgb = AvgEms; + #endif + #if DEBUG_PBR_FMS_EMS + color.rgb = FmsEms; + #endif + #if DEBUG_PBR_FSS_ESS_GGX + color.rgb = FssEssGGX; // spec + #endif + #if DEBUG_PBR_FSS_ESS_LAMBERT + color.rgb = FssEssLambert; // diffuse + #endif + #if DEBUG_PBR_FRESNEL + color.rgb = fresnelR; + #endif + #if DEBUG_PBR_IOR + color.rgb = vec3(IOR); + #endif + #if DEBUG_PBR_IRRADIANCE_RAW + color.rgb = debug_irradiance; + #endif + #if DEBUG_PBR_IRRADIANCE + color.rgb = irradiance; + #endif + #if DEBUG_PBR_KSPEC + color.rgb = kSpec; + #endif + #if DEBUG_PBR_REFLECT0_BASE + color.rgb = vec3(debug_reflect0); + #endif + #if DEBUG_PBR_REFLECT0_MIX + color.rgb = vec3(reflect0); + #endif + #if DEBUG_PBR_REFLECTANCE + color.rgb = vec3(reflectance); + #endif + #if DEBUG_PBR_REFLECTION_DIR + color.rgb = reflect(-v, n); // NOTE: equivalent to normalize(reflect(pos.xyz, norm.xyz)); + #endif + #if DEBUG_PBR_SPEC + color.rgb = colorSpec; + #endif + #if DEBUG_PBR_SPEC_REFLECTION + color.rgb = specLight; + #endif + #if DEBUG_PBR_SPEC_WEIGHT + color.rgb = vec3(specWeight); + #endif + #if DEBUG_PBR_V2C_RAW + color.rgb = v; + #endif + #if DEBUG_PBR_V2C_REMAP + color.rgb = v*0.5 + vec3(0.5); + #endif + + #if DEBUG_PBR_DA_RAW + color.rgb = vec3(debug_da); + #endif + #if DEBUG_PBR_DA_POW + color.rgb = vec3(da); + #endif + #if DEBUG_PBR_SKY_ADDITIVE + color.rgb = additive; + #endif + #if DEBUG_PBR_SKY_ATTEN + color.rgb = vec3(atten.r); + #endif + #if DEBUG_PBR_SUN_LIT + color.rgb = sunlit; + #endif + #if DEBUG_PBR_SUN_CONTRIB + color.rgb = sun_contrib; + #endif + #if DEBUG_PBR_LIGHT_TYPE + color.rgb = vec3(0); + #endif + frag_color.rgb = color.rgb; // PBR is done in linear + } +else +{ + diffuse.rgb = linear_to_srgb(diffuse.rgb); // SL-14035 - vec3 transmittance; - vec3 sky_irradiance; - vec3 sun_irradiance = GetSunAndSkyIrradiance(camPos, norm.xyz, sun_dir, sky_irradiance); - vec3 inscatter = GetSkyLuminanceToPoint(camPos, (pos / 1000.f) + vec3(0, 0, 6360.0f), scol, sun_dir, transmittance); + sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity); - vec3 radiance = scol * (sun_irradiance + sky_irradiance) + inscatter; - vec3 atmo_color = ColorFromRadiance(radiance); + amblit = max(ambenv, amblit); + color.rgb = amblit*ambocc; - col = atmo_color + indirect; - col *= transmittance; - col *= diffuse.rgb; + //float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); + //ambient *= 0.5; + //ambient *= ambient; + //ambient = (1.0 - ambient); + //color.rgb *= ambient; - vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + vec3 sun_contrib = min(da, scol) * sunlit; + color.rgb += sun_contrib; + color.rgb = min(color.rgb, vec3(1,1,1)); + color.rgb *= diffuse.rgb; - if (spec.a > 0.0) // specular reflection - { - // the old infinite-sky shiny reflection - // - float sa = dot(refnormpersp, sun_dir.xyz); - vec3 dumbshiny = scol * texture2D(lightFunc, vec2(sa, spec.a)).r * atmo_color; - - // add the two types of shiny together - vec3 spec_contrib = dumbshiny * spec.rgb * 0.25; - bloom = dot(spec_contrib, spec_contrib); - col += spec_contrib; - } + vec3 refnormpersp = reflect(pos.xyz, norm.xyz); - col = mix(col, diffuse.rgb, diffuse.a); + if (spec.a > 0.0) // specular reflection + { + float sa = dot(normalize(refnormpersp), light_dir.xyz); + vec3 dumbshiny = sunlit * scol * (texture2D(lightFunc, vec2(sa, spec.a)).r); - if (envIntensity > 0.0) - { //add environmentmap - vec3 env_vec = env_mat * refnormpersp; - vec3 sun_direction = (inv_modelview * vec4(sun_dir, 1.0)).xyz; - vec3 radiance_sun = GetSkyLuminance(camPos, env_vec, 0.0f, sun_direction, transmittance); - vec3 refcol = ColorFromRadiance(radiance_sun); - col = mix(col.rgb, refcol, envIntensity); - } - - /*if (norm.w < 0.5) - { - col = scaleSoftClipFrag(col); - }*/ - - #ifdef WATER_FOG - vec4 fogged = applyWaterFogView(pos,vec4(col, bloom)); - col = fogged.rgb; - bloom = fogged.a; - #endif + // add the two types of shiny together + vec3 spec_contrib = dumbshiny * spec.rgb; + bloom = dot(spec_contrib, spec_contrib) / 6; + color.rgb += spec_contrib; + + // add reflection map - EXPERIMENTAL WORK IN PROGRESS + applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz); } - //output linear since gamma correction happens down stream - frag_color.rgb = col; + color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a); + + if (envIntensity > 0.0) + { // add environmentmap + //fudge darker + legacyenv *= 0.5*diffuse.a+0.5; + applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity); + } + + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS)) + { + color = mix(atmosFragLighting(color, additive, atten), fullbrightAtmosTransportFrag(color, additive, atten), diffuse.a); + color = mix(scaleSoftClipFrag(color), fullbrightScaleSoftClip(color), diffuse.a); + } + +#ifdef WATER_FOG + vec4 fogged = applyWaterFogView(pos.xyz, vec4(color, bloom)); + color = fogged.rgb; + bloom = fogged.a; +#endif + #if DEBUG_PBR_LIGHT_TYPE + color.rgb = vec3(0); + #endif + // convert to linear as fullscreen lights need to sum in linear colorspace + // and will be gamma (re)corrected downstream... + //color = ambenv; + //color.b = diffuse.a; + frag_color.rgb = srgb_to_linear(color.rgb); +} +#if DEBUG_PBR_AMBOCC + frag_color.rgb = vec3(ambocc); +#endif +#if DEBUG_PBR_AMBENV + frag_color.rgb = ambenv; +#endif frag_color.a = bloom; } diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl deleted file mode 100644 index 9d872b8df8..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file class3/deferred/softenLightV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ -ATTRIBUTE vec3 position; - -VARYING vec2 vary_fragcoord; - -uniform mat4 modelview_projection_matrix; -uniform vec2 screen_res; - -void main() -{ - //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl index 56b0f4e5ce..41e40a07e7 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl @@ -1,9 +1,9 @@ /** - * @file spotLightF.glsl + * @file class3\deferred\spotLightF.glsl * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2007, Linden Research, Inc. + * Copyright (C) 2022, 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 @@ -28,6 +28,16 @@ /*[EXTRA_CODE_HERE]*/ +#define DEBUG_ANY_LIGHT_TYPE 0 // Output green light cone +#define DEBUG_LEG_LIGHT_TYPE 0 // Show Legacy objects in green +#define DEBUG_PBR_LIGHT_TYPE 0 // Show PBR objects in green +#define DEBUG_PBR_SPOT 0 +#define DEBUG_PBR_SPOT_DIFFUSE 0 +#define DEBUG_PBR_SPOT_SPECULAR 0 + +#define DEBUG_SPOT_NL 0 // monochome area effected by light +#define DEBUG_SPOT_ZERO 0 // Output zero for spotlight + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else @@ -38,10 +48,11 @@ uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; +uniform sampler2DRect emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl uniform samplerCube environmentMap; uniform sampler2DRect lightMap; uniform sampler2D noiseMap; -uniform sampler2D projectionMap; +uniform sampler2D projectionMap; // rgba uniform sampler2D lightFunc; uniform mat4 proj_mat; //screen space to light space @@ -71,217 +82,220 @@ uniform vec2 screen_res; uniform mat4 inv_proj; -vec3 getNorm(vec2 pos_screen); - -vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) -{ - vec4 ret = texture2DLod(projectionMap, tc, lod); - - vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); - - float det = min(lod/(proj_lod*0.5), 1.0); - - float d = min(dist.x, dist.y); - - d *= min(1, d * (proj_lod - lod)); - - float edge = 0.25*det; - - ret *= clamp(d/edge, 0.0, 1.0); - - return ret; -} - -vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) -{ - vec4 ret = texture2DLod(projectionMap, tc, lod); - - vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); - - float det = min(lod/(proj_lod*0.5), 1.0); - - float d = min(dist.x, dist.y); - - float edge = 0.25*det; - - ret *= clamp(d/edge, 0.0, 1.0); - - return ret; -} - -vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) -{ - vec4 ret = texture2DLod(projectionMap, tc, lod); - - vec2 dist = tc-vec2(0.5); - - float d = dot(dist,dist); - - ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); - - return ret; -} - +vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh ); +vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRoughness, float specWeight, float vh, float nl, float nv, float nh ); +void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); +bool clipProjectedLightVars(vec3 center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc ); +vec3 getLightIntensitySpot(vec3 lightColor, float lightRange, float lightDistance, vec3 v); +vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv); +vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv ); +vec3 getProjectedLightSpecularColor(vec3 pos, vec3 n); +vec2 getScreenXY(vec4 clip_point); +void initMaterial( vec3 diffuse, vec3 packedORM, out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight ); +vec3 srgb_to_linear(vec3 c); +vec4 texture2DLodSpecular(vec2 tc, float lod); vec4 getPosition(vec2 pos_screen); -void main() +void main() { - vec4 frag = vary_fragcoord; - frag.xyz /= frag.w; - frag.xyz = frag.xyz*0.5+0.5; - frag.xy *= screen_res; - - vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = trans_center.xyz-pos.xyz; - float dist = length(lv); - dist /= size; - if (dist > 1.0) +#if defined(LOCAL_LIGHT_KILL) + discard; +#else + vec3 final_color = vec3(0,0,0); + vec2 tc = getScreenXY(vary_fragcoord); + vec3 pos = getPosition(tc).xyz; + + vec3 lv; + vec4 proj_tc; + float dist, l_dist; + if (clipProjectedLightVars(trans_center, pos, dist, l_dist, lv, proj_tc)) { discard; } - + float shadow = 1.0; - + if (proj_shadow_idx >= 0) { - vec4 shd = texture2DRect(lightMap, frag.xy); + vec4 shd = texture2DRect(lightMap, tc); shadow = (proj_shadow_idx == 0) ? shd.b : shd.a; shadow += shadow_fade; shadow = clamp(shadow, 0.0, 1.0); } - - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; - float envIntensity = norm.z; - norm = getNorm(frag.xy); - - norm = normalize(norm); - float l_dist = -dot(lv, proj_n); - - vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); - if (proj_tc.z < 0.0) - { - discard; - } - - proj_tc.xyz /= proj_tc.w; - - float fa = (falloff*0.5) + 1.0; - float dist_atten = min(1.0 - (dist - 1.0 * (1.0 - fa)) / fa, 1.0); + + float envIntensity; + vec3 n; + vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + + float dist_atten = 1.0 - (dist + falloff)/(1.0 + falloff); dist_atten *= dist_atten; dist_atten *= 2.0; - if (dist_atten <= 0.0) { discard; } - - lv = proj_origin-pos.xyz; - lv = normalize(lv); - float da = dot(norm, lv); - - vec3 col = vec3(0,0,0); - - vec3 diff_tex = srgb_to_linear(texture2DRect(diffuseRect, frag.xy).rgb); - - vec4 spec = texture2DRect(specularRect, frag.xy); - - vec3 dlit = vec3(0, 0, 0); - - float noise = texture2D(noiseMap, frag.xy/128.0).b; - if (proj_tc.z > 0.0 && - proj_tc.x < 1.0 && - proj_tc.y < 1.0 && - proj_tc.x > 0.0 && - proj_tc.y > 0.0) + + lv = proj_origin-pos.xyz; // NOTE: Re-using lv + vec3 h, l, v = -normalize(pos); + float nh, nl, nv, vh, lightDist; + calcHalfVectors(lv, n, v, h, l, nh, nl, nv, vh, lightDist); + + vec3 diffuse = texture2DRect(diffuseRect, tc).rgb; + vec4 spec = texture2DRect(specularRect, tc); + vec3 dlit = vec3(0, 0, 0); + vec3 slit = vec3(0, 0, 0); + + if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { - float amb_da = proj_ambiance; - float lit = 0.0; - - if (da > 0.0) + vec3 colorDiffuse = vec3(0); + vec3 colorSpec = vec3(0); + vec3 colorEmissive = spec.rgb; // PBR sRGB Emissive. See: pbropaqueF.glsl + vec3 packedORM = texture2DRect(emissiveRect, tc).rgb; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl + float metal = packedORM.b; + + // We need this additional test inside a light's frustum since a spotlight's ambiance can be applied + if (proj_tc.x > 0.0 && proj_tc.x < 1.0 + && proj_tc.y > 0.0 && proj_tc.y < 1.0) { - lit = da * dist_atten * noise; - - float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); - float lod = diff * proj_lod; - - vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); - - dlit = color.rgb * plcol.rgb * plcol.a; - - col = dlit*lit*diff_tex*shadow; - amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; + float lit = 0.0; + float amb_da = 0.0; + + if (nl > 0.0) + { + amb_da += (nl*0.5 + 0.5) * proj_ambiance; + lit = nl * dist_atten; + + vec3 c_diff, reflect0, reflect90; + float alphaRough, specWeight; + initMaterial( diffuse, packedORM, alphaRough, c_diff, reflect0, reflect90, specWeight ); + + dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy ); + slit = getProjectedLightSpecularColor( pos, n ); + + colorDiffuse = shadow * dist_atten * nl * (dlit*0.5 + BRDFLambertian ( reflect0, reflect90, c_diff , specWeight, vh )); + colorSpec = shadow * dist_atten * nl * (slit + BRDFSpecularGGX( reflect0, reflect90, alphaRough, specWeight, vh, nl, nv, nh )); + + #if DEBUG_PBR_SPOT_DIFFUSE + colorDiffuse = dlit.rgb; colorSpec = vec3(0); + #endif + #if DEBUG_PBR_SPOT_SPECULAR + colorDiffuse = vec3(0); colorSpec = slit.rgb; + #endif + #if DEBUG_PBR_SPOT + colorDiffuse = dlit; colorSpec = vec3(0); + colorDiffuse *= nl; + colorDiffuse *= shadow; + #endif + } + + vec3 amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, 1.0, proj_tc.xy ); + colorDiffuse += diffuse.rgb * amb_rgb; + } - - //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); - vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); - - amb_da += (da*da*0.5+0.5)*(1.0-shadow)*proj_ambiance; - - amb_da *= dist_atten * noise; - - amb_da = min(amb_da, 1.0-lit); - - col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; - } - - if (spec.a > 0.0) + #if DEBUG_PBR_LIGHT_TYPE + colorDiffuse = vec3(0.5,0,0); colorSpec = vec3(0.0); + #endif + + final_color = colorDiffuse + colorSpec; + } + else { - dlit *= min(da*6.0, 1.0) * dist_atten; - vec3 npos = -normalize(pos); - - //vec3 ref = dot(pos+lv, norm); - vec3 h = normalize(lv+npos); - float nh = dot(norm, h); - float nv = dot(norm, npos); - float vh = dot(npos, h); - float sa = nh; - float fres = pow(1 - dot(h, npos), 5)*0.4+0.5; - - float gtdenom = 2 * nh; - float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); - - if (nh > 0.0) + float noise = texture2D(noiseMap, tc/128.0).b; + if (proj_tc.z > 0.0 && + proj_tc.x < 1.0 && + proj_tc.y < 1.0 && + proj_tc.x > 0.0 && + proj_tc.y > 0.0) { - float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); - col += dlit*scol*spec.rgb*shadow; + float amb_da = proj_ambiance; + float lit = 0.0; + + if (nl > 0.0) + { + lit = nl * dist_atten * noise; + + dlit = getProjectedLightDiffuseColor( l_dist, proj_tc.xy ); + + final_color = dlit*lit*diffuse*shadow; + + amb_da += (nl*0.5+0.5) /* * (1.0-shadow) */ * proj_ambiance; + } + + vec3 amb_rgb = getProjectedLightAmbiance( amb_da, dist_atten, lit, nl, noise, proj_tc.xy ); + final_color += diffuse.rgb*amb_rgb; + #if DEBUG_LEG_LIGHT_TYPE + final_color = vec3(0,0.5,0); + #endif } - } - - if (envIntensity > 0.0) - { - vec3 ref = reflect(normalize(pos), norm); - - //project from point pos in direction ref to plane proj_p, proj_n - vec3 pdelta = proj_p-pos; - float ds = dot(ref, proj_n); - - if (ds < 0.0) + if (spec.a > 0.0) { - vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - - vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); + dlit *= min(nl*6.0, 1.0) * dist_atten; + float fres = pow(1 - dot(h, v), 5)*0.4+0.5; - if (stc.z > 0.0) + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * nl / vh)); + + if (nh > 0.0) { - stc /= stc.w; - - if (stc.x < 1.0 && - stc.y < 1.0 && - stc.x > 0.0 && - stc.y > 0.0) + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*nl); + vec3 speccol = dlit*scol*spec.rgb*shadow; + speccol = clamp(speccol, vec3(0), vec3(1)); + final_color += speccol; + } + } + + if (envIntensity > 0.0) + { + vec3 ref = reflect(normalize(pos), n); + + //project from point pos in direction ref to plane proj_p, proj_n + vec3 pdelta = proj_p-pos; + float ds = dot(ref, proj_n); + + if (ds < 0.0) + { + vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; + + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); + + if (stc.z > 0.0) { - col += color.rgb * texture2DLodSpecular(projectionMap, stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity; + stc /= stc.w; + + if (stc.x < 1.0 && + stc.y < 1.0 && + stc.x > 0.0 && + stc.y > 0.0) + { + final_color += color.rgb * texture2DLodSpecular(stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity; + } } } } } - + +#if DEBUG_SPOT_DIFFUSE + final_color = vec3(nl * dist_atten); +#endif +#if DEBUG_SPOT_NL + final_color = vec3(nl); +#endif +#if DEBUG_SPOT_ZERO + final_color = vec3(0,0,0); +#endif +#if DEBUG_ANY_LIGHT_TYPE + final_color = vec3(0,0.3333,0); +#endif + //not sure why, but this line prevents MATBUG-194 - col = max(col, vec3(0.0)); + final_color = max(final_color, vec3(0.0)); - frag_color.rgb = col; + //output linear colors as gamma correction happens down stream + frag_color.rgb = final_color; frag_color.a = 0.0; +#endif // LOCAL_LIGHT_KILL } diff --git a/indra/newview/app_settings/shaders/class3/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/sunLightF.glsl deleted file mode 100644 index 112b498c90..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/sunLightF.glsl +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file class3\deferred\sunLightF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -/*[EXTRA_CODE_HERE]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -//class 2, shadows, no SSAO - -// Inputs -VARYING vec2 vary_fragcoord; - -vec4 getPosition(vec2 pos_screen); -vec3 getNorm(vec2 pos_screen); - -float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); -float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen); - -void main() -{ - vec2 pos_screen = vary_fragcoord.xy; - vec4 pos = getPosition(pos_screen); - vec3 norm = getNorm(pos_screen); - - frag_color.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); - frag_color.g = 1.0f; - frag_color.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); - frag_color.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class3/deferred/sunLightSSAOF.glsl deleted file mode 100644 index 342a2ff3ed..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/sunLightSSAOF.glsl +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file class3\deferred\sunLightSSAOF.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -/*[EXTRA_CODE_HERE]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -//class 2 -- shadows and SSAO - -// Inputs -VARYING vec2 vary_fragcoord; - -uniform vec3 sun_dir; - -vec4 getPosition(vec2 pos_screen); -vec3 getNorm(vec2 pos_screen); - -float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); -float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen); - -//calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen); - -void main() -{ - vec2 pos_screen = vary_fragcoord.xy; - vec4 pos = getPosition(pos_screen); - vec3 norm = getNorm(pos_screen); - - frag_color.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); - frag_color.b = calcAmbientOcclusion(pos, norm, pos_screen); - frag_color.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); - frag_color.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/treeShadowF.glsl b/indra/newview/app_settings/shaders/class3/deferred/treeShadowF.glsl deleted file mode 100644 index 41673d1669..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/treeShadowF.glsl +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file treeShadowF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform float minimum_alpha; - -uniform sampler2D diffuseMap; - -VARYING vec4 pos; -VARYING vec2 vary_texcoord0; - -vec4 computeMoments(float d, float a); - -void main() -{ - float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a; - - if (alpha < minimum_alpha) - { - discard; - } - - frag_color = computeMoments(length(pos), 1.0); - -#if !defined(DEPTH_CLAMP) - gl_FragDepth = max(pos.z/pos.w*0.5+0.5, 0.0); -#endif - -} - diff --git a/indra/newview/app_settings/shaders/class3/deferred/treeShadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/treeShadowV.glsl deleted file mode 100644 index 15e769ac10..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/treeShadowV.glsl +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @file treeShadowV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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 texture_matrix0; -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; - -VARYING vec4 pos; -VARYING vec2 vary_texcoord0; - -void main() -{ - //transform vertex - pos = modelview_projection_matrix*vec4(position.xyz, 1.0); - - gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); - - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/deferred/underWaterF.glsl deleted file mode 100644 index 540226e672..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/underWaterF.glsl +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @file underWaterF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_data[3]; -#else -#define frag_data gl_FragData -#endif - -uniform sampler2D diffuseMap; -uniform sampler2D bumpMap; -uniform sampler2D screenTex; -uniform sampler2D refTex; -uniform sampler2D screenDepth; - -uniform vec4 fogCol; -uniform vec3 lightDir; -uniform vec3 specular; -uniform float lightExp; -uniform vec2 fbScale; -uniform float refScale; -uniform float znear; -uniform float zfar; -uniform float kd; -uniform vec4 waterPlane; -uniform vec3 eyeVec; -uniform vec4 waterFogColor; -uniform float waterFogDensity; -uniform float waterFogKS; -uniform vec2 screenRes; - -//bigWave is (refCoord.w, view.w); -VARYING vec4 refCoord; -VARYING vec4 littleWave; -VARYING vec4 view; - -vec2 encode_normal(vec3 n); - -vec4 applyWaterFog(vec4 color, vec3 viewVec) -{ - //normalize view vector - vec3 view = normalize(viewVec); - float es = -view.z; - - //find intersection point with water plane and eye vector - - //get eye depth - float e0 = max(-waterPlane.w, 0.0); - - //get object depth - float depth = length(viewVec); - - //get "thickness" of water - float l = max(depth, 0.1); - - float kd = waterFogDensity; - float ks = waterFogKS; - vec4 kc = waterFogColor; - - float F = 0.98; - - float t1 = -kd * pow(F, ks * e0); - float t2 = kd + ks * es; - float t3 = pow(F, t2*l) - 1.0; - - float L = min(t1/t2*t3, 1.0); - - float D = pow(0.98, l*kd); - return color * D + kc * L; -} - -void main() -{ - vec4 color; - - //get detail normals - vec3 wave1 = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0; - vec3 wave2 = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0; - vec3 wave3 = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0; - vec3 wavef = normalize(wave1+wave2+wave3); - - //figure out distortion vector (ripply) - vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; - distort = distort+wavef.xy*refScale; - - vec4 fb = texture2D(screenTex, distort); - - frag_data[0] = vec4(fb.rgb, 1.0); // diffuse - frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec - frag_data[2] = vec4(encode_normal(wavef), 0.0, 0.0); // normalxyz, displace -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterF.glsl deleted file mode 100644 index c65cf48c67..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/waterF.glsl +++ /dev/null @@ -1,174 +0,0 @@ -/** - * @file waterF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -/*[EXTRA_CODE_HERE]*/ - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_data[3]; -#else -#define frag_data gl_FragData -#endif - -uniform sampler2D bumpMap; -uniform sampler2D bumpMap2; -uniform float blend_factor; -uniform sampler2D screenTex; -uniform sampler2D refTex; - -uniform float sunAngle; -uniform float sunAngle2; -uniform vec3 lightDir; -uniform vec3 specular; -uniform float lightExp; -uniform float refScale; -uniform float kd; -uniform vec2 screenRes; -uniform vec3 normScale; -uniform float fresnelScale; -uniform float fresnelOffset; -uniform float blurMultiplier; -uniform vec2 screen_res; -uniform mat4 norm_mat; //region space to screen space - -//bigWave is (refCoord.w, view.w); -VARYING vec4 refCoord; -VARYING vec4 littleWave; -VARYING vec4 view; -VARYING vec4 vary_position; - -vec3 scaleSoftClip(vec3 c); -vec2 encode_normal(vec3 n); - -vec3 BlendNormal(vec3 bump1, vec3 bump2) -{ - //vec3 normal = bump1.xyz * vec3( 2.0, 2.0, 2.0) - vec3(1.0, 1.0, 0.0); - //vec3 normal2 = bump2.xyz * vec3(-2.0, -2.0, 2.0) + vec3(1.0, 1.0, -1.0); - //vec3 n = normalize(normal * dot(normal, normal2) - (normal2 * normal.z)); - vec3 n = normalize(mix(bump1, bump2, blend_factor)); - return n; -} - -void main() -{ - vec4 color; - float dist = length(view.xy); - - //normalize view vector - vec3 viewVec = normalize(view.xyz); - - //get wave normals - vec3 wave1_a = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0; - vec3 wave2_a = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0; - vec3 wave3_a = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0; - - - vec3 wave1_b = texture2D(bumpMap2, vec2(refCoord.w, view.w)).xyz*2.0-1.0; - vec3 wave2_b = texture2D(bumpMap2, littleWave.xy).xyz*2.0-1.0; - vec3 wave3_b = texture2D(bumpMap2, littleWave.zw).xyz*2.0-1.0; - - vec3 wave1 = BlendNormal(wave1_a, wave1_b); - vec3 wave2 = BlendNormal(wave2_a, wave2_b); - vec3 wave3 = BlendNormal(wave3_a, wave3_b); - - //get base fresnel components - - vec3 df = vec3( - dot(viewVec, wave1), - dot(viewVec, (wave2 + wave3) * 0.5), - dot(viewVec, wave3) - ) * fresnelScale + fresnelOffset; - df *= df; - - vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; - - float dist2 = dist; - dist = max(dist, 5.0); - - float dmod = sqrt(dist); - - vec2 dmod_scale = vec2(dmod*dmod, dmod); - - //get reflected color - vec2 refdistort1 = wave1.xy*normScale.x; - vec2 refvec1 = distort+refdistort1/dmod_scale; - vec4 refcol1 = texture2D(refTex, refvec1); - - vec2 refdistort2 = wave2.xy*normScale.y; - vec2 refvec2 = distort+refdistort2/dmod_scale; - vec4 refcol2 = texture2D(refTex, refvec2); - - vec2 refdistort3 = wave3.xy*normScale.z; - vec2 refvec3 = distort+refdistort3/dmod_scale; - vec4 refcol3 = texture2D(refTex, refvec3); - - vec4 refcol = refcol1 + refcol2 + refcol3; - float df1 = df.x + df.y + df.z; - refcol *= df1 * 0.333; - - vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5; - wavef.z *= max(-viewVec.z, 0.1); - wavef = normalize(wavef); - - float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset; - - vec2 refdistort4 = wavef.xy*0.125; - refdistort4.y -= abs(refdistort4.y); - vec2 refvec4 = distort+refdistort4/dmod; - float dweight = min(dist2*blurMultiplier, 1.0); - vec4 baseCol = texture2D(refTex, refvec4); - - refcol = mix(baseCol*df2, refcol, dweight); - - //get specular component - float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0); - - //harden specular - spec = pow(spec, 128.0); - - //figure out distortion vector (ripply) - vec2 distort2 = distort+wavef.xy*refScale/max(dmod*df1, 1.0); - - vec4 fb = texture2D(screenTex, distort2); - - //mix with reflection - // Note we actually want to use just df1, but multiplying by 0.999999 gets around an nvidia compiler bug - color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999); - - color.rgb *= 2.0f; - color.rgb = scaleSoftClip(color.rgb); - - vec4 pos = vary_position; - - color.rgb += spec * specular; - color.a = spec * sunAngle2; - - vec3 screenspacewavef = normalize((norm_mat*vec4(wavef, 1.0)).xyz); - - frag_data[0] = vec4(color.rgb, color); // diffuse - frag_data[1] = vec4(spec * specular, spec); // speccolor, spec - frag_data[2] = vec4(encode_normal(wavef.xyz), 0.05, 0);// normalxy, 0, 0 -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterV.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterV.glsl deleted file mode 100644 index 02000d90ca..0000000000 --- a/indra/newview/app_settings/shaders/class3/deferred/waterV.glsl +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file waterV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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_matrix; -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - - -uniform vec2 d1; -uniform vec2 d2; -uniform float time; -uniform vec3 eyeVec; -uniform float waterHeight; - -VARYING vec4 refCoord; -VARYING vec4 littleWave; -VARYING vec4 view; - -VARYING vec4 vary_position; - -float wave(vec2 v, float t, float f, vec2 d, float s) -{ - return (dot(d, v)*f + t*s)*f; -} - -void main() -{ - //transform vertex - vec4 pos = vec4(position.xyz, 1.0); - mat4 modelViewProj = modelview_projection_matrix; - - vec4 oPosition; - - //get view vector - vec3 oEyeVec; - oEyeVec.xyz = pos.xyz-eyeVec; - - float d = length(oEyeVec.xy); - float ld = min(d, 2560.0); - - pos.xy = eyeVec.xy + oEyeVec.xy/d*ld; - view.xyz = oEyeVec; - - d = clamp(ld/1536.0-0.5, 0.0, 1.0); - d *= d; - - oPosition = vec4(position, 1.0); - oPosition.z = mix(oPosition.z, max(eyeVec.z*0.75, 0.0), d); - vary_position = modelview_matrix * oPosition; - oPosition = modelViewProj * oPosition; - - refCoord.xyz = oPosition.xyz + vec3(0,0,0.2); - - //get wave position parameter (create sweeping horizontal waves) - vec3 v = pos.xyz; - v.x += (cos(v.x*0.08/*+time*0.01*/)+sin(v.y*0.02))*6.0; - - //push position for further horizon effect. - pos.xyz = oEyeVec.xyz*(waterHeight/oEyeVec.z); - pos.w = 1.0; - pos = modelview_matrix*pos; - - //pass wave parameters to pixel shader - vec2 bigWave = (v.xy) * vec2(0.04,0.04) + d1 * time * 0.055; - //get two normal map (detail map) texture coordinates - littleWave.xy = (v.xy) * vec2(0.45, 0.9) + d2 * time * 0.13; - littleWave.zw = (v.xy) * vec2(0.1, 0.2) + d1 * time * 0.1; - view.w = bigWave.y; - refCoord.w = bigWave.x; - - gl_Position = oPosition; -} diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index e04e38b9de..6b4ab1be17 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -1,4 +1,4 @@ -version 34 +version 36 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -28,7 +28,7 @@ version 34 // list all RenderAnisotropic 1 1 -RenderAvatarCloth 1 1 +RenderAvatarCloth 0 0 RenderAvatarLODFactor 1 1.0 RenderAvatarPhysicsLODFactor 1 1.0 RenderAvatarMaxNonImpostors 1 16 @@ -62,6 +62,8 @@ Disregard128DefaultDrawDistance 1 1 Disregard96DefaultDrawDistance 1 1 RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 +RenderPBR 1 1 +RenderReflectionProbeCount 1 256 RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderUseAdvancedAtmospherics 1 0 @@ -78,7 +80,6 @@ RenderGLMultiThreaded 1 1 // list Low RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0 RenderAvatarPhysicsLODFactor 1 0 RenderAvatarMaxNonImpostors 1 3 @@ -88,15 +89,13 @@ RenderFlexTimeFactor 1 0 RenderGlowResolutionPow 1 8 RenderLocalLights 1 0 RenderMaxPartCount 1 0 -RenderObjectBump 1 0 RenderReflectionDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 +RenderPBR 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -108,7 +107,6 @@ RenderFSAASamples 1 0 // list LowMid RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0.5 RenderAvatarMaxComplexity 1 100000 RenderAvatarPhysicsLODFactor 1 0.75 @@ -116,7 +114,6 @@ RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 RenderMaxPartCount 1 2048 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -124,8 +121,7 @@ RenderTerrainLODFactor 1 1.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 +RenderPBR 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -137,7 +133,6 @@ RenderFSAASamples 1 0 // list Mid RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 200000 RenderAvatarPhysicsLODFactor 1 1.0 @@ -145,7 +140,6 @@ RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -153,8 +147,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -166,7 +158,6 @@ RenderFSAASamples 1 2 // list MidHigh RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 250000 RenderAvatarPhysicsLODFactor 1 1.0 @@ -174,7 +165,6 @@ RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -182,8 +172,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -195,7 +183,6 @@ RenderFSAASamples 1 2 // list High RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 300000 RenderAvatarPhysicsLODFactor 1 1.0 @@ -203,7 +190,6 @@ RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -211,8 +197,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -224,7 +208,6 @@ RenderFSAASamples 1 2 // list HighUltra RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 350000 RenderAvatarPhysicsLODFactor 1 1.0 @@ -232,7 +215,6 @@ RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -240,8 +222,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 @@ -253,7 +233,6 @@ RenderFSAASamples 1 2 // list Ultra RenderAnisotropic 1 1 -RenderAvatarCloth 1 1 RenderAvatarLODFactor 1 1.0 RenderAvatarPhysicsLODFactor 1 1.0 RenderFarClip 1 256 @@ -261,7 +240,6 @@ RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderLocalLights 1 1 RenderMaxPartCount 1 8192 -RenderObjectBump 1 1 RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 @@ -270,7 +248,6 @@ RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 -RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 @@ -281,8 +258,8 @@ RenderFSAASamples 1 2 // list Unknown RenderShadowDetail 1 0 -RenderDeferred 1 0 RenderDeferredSSAO 1 0 +RenderPBR 1 0 RenderUseAdvancedAtmospherics 1 0 // @@ -296,18 +273,15 @@ RenderCompressTextures 1 0 // list safe RenderAnisotropic 1 0 -RenderAvatarCloth 0 0 RenderAvatarMaxNonImpostors 1 16 RenderAvatarMaxComplexity 1 80000 -RenderObjectBump 0 0 RenderLocalLights 1 0 RenderMaxPartCount 1 1024 RenderTerrainDetail 1 0 RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 RenderDeferredSSAO 0 0 RenderShadowDetail 0 0 +RenderPBR 1 0 list Intel RenderAnisotropic 1 0 @@ -317,8 +291,11 @@ RenderGLContextCoreProfile 1 0 // AMD cards generally perform better when not using VBOs for streaming data // AMD cards also prefer an OpenGL Compatibility Profile Context +// HACK: Current AMD drivers have bugged cubemap arrays, limit number of reflection probes to 16 list AMD RenderUseStreamVBO 1 0 RenderGLContextCoreProfile 1 0 +RenderReflectionProbeCount 1 16 + diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index d319d26e1f..311b669d7f 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -1,4 +1,4 @@ -version 38 +version 39 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -28,7 +28,7 @@ version 38 // list all RenderAnisotropic 1 0 -RenderAvatarCloth 1 1 +RenderAvatarCloth 0 0 RenderAvatarLODFactor 1 1.0 RenderAvatarPhysicsLODFactor 1 1.0 RenderAvatarMaxNonImpostors 1 16 @@ -63,6 +63,7 @@ Disregard96DefaultDrawDistance 1 1 RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 RenderDeferred 1 1 +RenderPBR 1 1 RenderDeferredSSAO 1 1 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 @@ -77,7 +78,6 @@ RenderGLMultiThreaded 1 0 // list Low RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0 RenderAvatarPhysicsLODFactor 1 0 RenderAvatarMaxNonImpostors 1 3 @@ -87,15 +87,13 @@ RenderFlexTimeFactor 1 0 RenderGlowResolutionPow 1 8 RenderLocalLights 1 0 RenderMaxPartCount 1 0 -RenderObjectBump 1 0 RenderReflectionDetail 1 0 RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 0.5 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 +RenderPBR 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -107,7 +105,6 @@ RenderFSAASamples 1 0 // list LowMid RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0.5 RenderAvatarMaxComplexity 1 100000 RenderAvatarPhysicsLODFactor 1 0.75 @@ -115,7 +112,6 @@ RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 RenderMaxPartCount 1 2048 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -123,8 +119,7 @@ RenderTerrainLODFactor 1 1.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 +RenderPBR 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -136,7 +131,6 @@ RenderFSAASamples 1 0 // list Mid RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 200000 RenderAvatarPhysicsLODFactor 1 1.0 @@ -144,7 +138,6 @@ RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -152,8 +145,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -165,7 +156,6 @@ RenderFSAASamples 1 2 // list MidHigh RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 250000 RenderAvatarPhysicsLODFactor 1 1.0 @@ -173,7 +163,6 @@ RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -181,8 +170,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -194,7 +181,6 @@ RenderFSAASamples 1 2 // list High RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 300000 RenderAvatarPhysicsLODFactor 1 1.0 @@ -202,7 +188,6 @@ RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -210,8 +195,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -223,7 +206,6 @@ RenderFSAASamples 1 2 // list HighUltra RenderAnisotropic 1 1 -RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 350000 RenderAvatarPhysicsLODFactor 1 1.0 @@ -231,7 +213,6 @@ RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderMaxPartCount 1 4096 -RenderObjectBump 1 1 RenderLocalLights 1 1 RenderReflectionDetail 1 0 RenderTerrainDetail 1 1 @@ -239,8 +220,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 1 -RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderShadowDetail 1 2 RenderUseAdvancedAtmospherics 1 0 @@ -252,7 +231,6 @@ RenderFSAASamples 1 2 // list Ultra RenderAnisotropic 1 1 -RenderAvatarCloth 1 1 RenderAvatarLODFactor 1 1.0 RenderAvatarPhysicsLODFactor 1 1.0 RenderFarClip 1 256 @@ -260,7 +238,6 @@ RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 RenderLocalLights 1 1 RenderMaxPartCount 1 8192 -RenderObjectBump 1 1 RenderReflectionDetail 1 4 RenderTerrainDetail 1 1 RenderTerrainLODFactor 1 2.0 @@ -269,7 +246,6 @@ RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 -RenderDeferred 1 1 RenderDeferredSSAO 1 1 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 2 @@ -280,7 +256,7 @@ RenderFSAASamples 1 2 // list Unknown RenderShadowDetail 1 0 -RenderDeferred 1 0 +RenderPBR 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 @@ -296,16 +272,13 @@ RenderCompressTextures 1 0 // list safe RenderAnisotropic 1 0 -RenderAvatarCloth 0 0 RenderAvatarMaxNonImpostors 1 16 RenderAvatarMaxComplexity 1 80000 -RenderObjectBump 0 0 RenderLocalLights 1 0 RenderMaxPartCount 1 1024 RenderTerrainDetail 1 0 RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 +RenderPBR 1 0 RenderDeferredSSAO 0 0 RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt index fba6a55da3..29b5a919bd 100644 --- a/indra/newview/licenses-mac.txt +++ b/indra/newview/licenses-mac.txt @@ -719,3 +719,55 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +============ +tinygltf +============ +MIT License + +Copyright (c) 2017 Syoyo Fujita, Aurélien Chatelain and many contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +============== +Vulkan GLTF +============== +MIT License + +Copyright (c) 2018 Sascha Willems + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt index 837d92139d..eddc9a4475 100644 --- a/indra/newview/licenses-win32.txt +++ b/indra/newview/licenses-win32.txt @@ -796,3 +796,52 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +============ +tinygltf +============ +MIT License + +Copyright (c) 2017 Syoyo Fujita, Aurélien Chatelain and many contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +============== +Vulkan GLTF +============== +MIT License + +Copyright (c) 2018 Sascha Willems + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index b79af04c36..7f6f6e5997 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -713,6 +713,12 @@ void LLAgent::moveYaw(F32 mag, bool reset_view) setControlFlags(AGENT_CONTROL_YAW_NEG); } + U32 mask = AGENT_CONTROL_YAW_POS | AGENT_CONTROL_YAW_NEG; + if ((getControlFlags() & mask) == mask) + { + gAgentCamera.setYawKey(0); + } + if (reset_view) { gAgentCamera.resetView(); @@ -2005,6 +2011,27 @@ void LLAgent::updateAgentPosition(const F32 dt, const F32 yaw_radians, const S32 // gAgentCamera.updateLookAt(mouse_x, mouse_y); + + // When agent has no parents, position updates come from setPositionAgent() + // But when agent has a parent (ex: is seated), position remains unchanged + // relative to parent and no parent's position update trigger + // setPositionAgent(). + // But EEP's sky track selection still needs an update if agent has a parent + // and parent moves (ex: vehicles). + if (isAgentAvatarValid() + && gAgentAvatarp->getParent() + && !mOnPositionChanged.empty() + ) + { + LLVector3d new_position = getPositionGlobal(); + if ((mLastTestGlobal - new_position).lengthSquared() > 1.0) + { + // If the position has changed by more than 1 meter since the last time we triggered. + // filters out some noise. + mLastTestGlobal = new_position; + mOnPositionChanged(mFrameAgent.getOrigin(), new_position); + } + } } // friends and operators diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 84a41113be..57a59d81c4 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -401,10 +401,9 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi LLQuaternion obj_rot = object->getRenderRotation(); LLVector3 obj_pos = object->getRenderPosition(); - BOOL is_avatar = object->isAvatar(); // if is avatar - don't do any funk heuristics to position the focal point // see DEV-30589 - if (is_avatar) + if (object->isAvatar() || (object->isAnimatedObject() && object->getControlAvatar())) { return original_focus_point - obj_pos; } @@ -529,7 +528,6 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi // or keep the focus point in the object middle when (relatively) far // NOTE: leave focus point in middle of avatars, since the behavior you want when alt-zooming on avatars // is almost always "tumble about middle" and not "spin around surface point" - if (!is_avatar) { LLVector3 obj_rel = original_focus_point - object->getRenderPosition(); @@ -1188,12 +1186,18 @@ void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y) static LLTrace::BlockTimerStatHandle FTM_UPDATE_CAMERA("Camera"); +extern BOOL gCubeSnapshot; + //----------------------------------------------------------------------------- // updateCamera() //----------------------------------------------------------------------------- void LLAgentCamera::updateCamera() { LL_RECORD_BLOCK_TIME(FTM_UPDATE_CAMERA); + if (gCubeSnapshot) + { + return; + } // - changed camera_skyward to the new global "mCameraUpVector" mCameraUpVector = LLVector3::z_axis; @@ -1417,7 +1421,7 @@ void LLAgentCamera::updateCamera() F32 smoothing = LLSmoothInterpolation::getInterpolant(gSavedSettings.getF32("CameraPositionSmoothing") * SMOOTHING_HALF_LIFE, FALSE); - if (!mFocusObject) // we differentiate on avatar mode + if (mFocusOnAvatar && !mFocusObject) // we differentiate on avatar mode { // for avatar-relative focus, we smooth in avatar space - // the avatar moves too jerkily w/r/t global space to smooth there. diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index be168ff5dd..2e769dc737 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -37,6 +37,7 @@ #include "llgesturemgr.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llinventoryobserver.h" #include "llinventorypanel.h" #include "lllocaltextureobject.h" @@ -1582,6 +1583,14 @@ void LLAgentWearables::editWearable(const LLUUID& item_id) return; } + if (!item->isFinished()) + { + LL_WARNS() << "Tried to edit wearable that isn't loaded" << LL_ENDL; + // Restart fetch or put item to the front + LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false); + return; + } + LLViewerWearable* wearable = gAgentWearables.getWearableFromItemID(item_id); if (!wearable) { @@ -1595,6 +1604,18 @@ void LLAgentWearables::editWearable(const LLUUID& item_id) return; } + S32 shape_count = gAgentWearables.getWearableCount(LLWearableType::WT_SHAPE); + S32 hair_count = gAgentWearables.getWearableCount(LLWearableType::WT_HAIR); + S32 eye_count = gAgentWearables.getWearableCount(LLWearableType::WT_EYES); + S32 skin_count = gAgentWearables.getWearableCount(LLWearableType::WT_SKIN); + if (!shape_count || !hair_count || !eye_count || !skin_count) + { + // Don't let user edit wearables if avatar is cloud due to missing parts. + // Let user edit wearables if avatar is cloud due to missing textures. + LL_WARNS() << "Cannot modify wearable. Avatar is cloud and missing parts." << LL_ENDL; + return; + } + const BOOL disable_camera_switch = LLWearableType::getInstance()->getDisableCameraSwitch(wearable->getType()); LLPanel* panel = LLFloaterSidePanelContainer::getPanel("appearance"); LLSidepanelAppearance::editWearable(wearable, panel, disable_camera_switch); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 1a38f2da91..0e2828332e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -566,12 +566,12 @@ static void settings_to_globals() static void settings_modify() { LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); - LLPipeline::sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - LLPipeline::sRenderDeferred = LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred"); + LLPipeline::sRenderBump = TRUE; // FALSE is deprecated -- gSavedSettings.getBOOL("RenderObjectBump"); + LLPipeline::sRenderDeferred = TRUE; // FALSE is deprecated -- LLPipeline::sRenderBump&& gSavedSettings.getBOOL("RenderDeferred"); LLRenderTarget::sUseFBO = LLPipeline::sRenderDeferred; LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; // square lod factor to get exponential range of [1,4] - gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession; + gDebugGL = gDebugGLSession || gDebugSession; gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline"); } @@ -1124,7 +1124,8 @@ bool LLAppViewer::init() gGLActive = FALSE; #if LL_RELEASE_FOR_DOWNLOAD - if (!gSavedSettings.getBOOL("CmdLineSkipUpdater")) + // Skip updater if this is a non-interactive instance + if (!gSavedSettings.getBOOL("CmdLineSkipUpdater") && !gNonInteractive) { LLProcess::Params updater; updater.desc = "updater process"; @@ -1505,22 +1506,23 @@ bool LLAppViewer::doFrame() // Render scene. // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 - if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Display" ) - pingMainloopTimeout("Main:Display"); - gGLActive = TRUE; + if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Display"); + pingMainloopTimeout("Main:Display"); + gGLActive = TRUE; - display(); + display(); - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Snapshot" ) - pingMainloopTimeout("Main:Snapshot"); - LLFloaterSnapshot::update(); // take snapshots - LLFloaterOutfitSnapshot::update(); - gGLActive = FALSE; - } - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Snapshot"); + pingMainloopTimeout("Main:Snapshot"); + gPipeline.mReflectionMapManager.update(); + LLFloaterSnapshot::update(); // take snapshots + LLFloaterOutfitSnapshot::update(); + gGLActive = FALSE; + } + } } { @@ -2693,19 +2695,14 @@ bool LLAppViewer::initConfiguration() if (clp.hasOption("graphicslevel")) { - // User explicitly requested --graphicslevel on the command line. We - // expect this switch has already set RenderQualityPerformance. Check - // that value for validity. - U32 graphicslevel = gSavedSettings.getU32("RenderQualityPerformance"); - if (LLFeatureManager::instance().isValidGraphicsLevel(graphicslevel)) - { - // graphicslevel is valid: save it and engage it later. Capture - // the requested value separately from the settings variable - // because, if this is the first run, LLViewerWindow's constructor - // will call LLFeatureManager::applyRecommendedSettings(), which - // overwrites this settings variable! - mForceGraphicsLevel = graphicslevel; - } + // User explicitly requested --graphicslevel on the command line. We + // expect this switch has already set RenderQualityPerformance. Check + // that value for validity later. + // Capture the requested value separately from the settings variable + // because, if this is the first run, LLViewerWindow's constructor + // will call LLFeatureManager::applyRecommendedSettings(), which + // overwrites this settings variable! + mForceGraphicsLevel = gSavedSettings.getU32("RenderQualityPerformance"); } LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); @@ -2719,6 +2716,15 @@ bool LLAppViewer::initConfiguration() ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log")); } + if (gSavedSettings.getBOOL("RenderDebugGLSession")) + { + gDebugGLSession = TRUE; + gDebugGL = TRUE; + // gDebugGL can cause excessive logging + // so it's limited to a single session + gSavedSettings.setBOOL("RenderDebugGLSession", FALSE); + } + const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) { @@ -3054,7 +3060,7 @@ bool LLAppViewer::initWindow() // Initialize GL stuff // - if (mForceGraphicsLevel) + if (mForceGraphicsLevel && (LLFeatureManager::instance().isValidGraphicsLevel(*mForceGraphicsLevel))) { LLFeatureManager::getInstance()->setGraphicsLevel(*mForceGraphicsLevel, false); gSavedSettings.setU32("RenderQualityPerformance", *mForceGraphicsLevel); @@ -3115,6 +3121,11 @@ bool LLAppViewer::isUpdaterMissing() return mUpdaterNotFound; } +bool LLAppViewer::waitForUpdater() +{ + return !gSavedSettings.getBOOL("CmdLineSkipUpdater") && !mUpdaterNotFound && !gNonInteractive; +} + void LLAppViewer::writeDebugInfo(bool isStatic) { #if LL_WINDOWS && LL_BUGSPLAT @@ -3195,7 +3206,28 @@ LLSD LLAppViewer::getViewerInfo() const info["GRAPHICS_CARD"] = ll_safe_string((const char*)(glGetString(GL_RENDERER))); #if LL_WINDOWS - std::string drvinfo = gDXHardware.getDriverVersionWMI(); + std::string drvinfo; + + if (gGLManager.mIsIntel) + { + drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_INTEL); + } + else if (gGLManager.mIsNVIDIA) + { + drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_NVIDIA); + } + else if (gGLManager.mIsAMD) + { + drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_AMD); + } + + if (drvinfo.empty()) + { + // Generic/substitute windows driver? Unknown vendor? + LL_WARNS("DriverVersion") << "Vendor based driver search failed, searching for any driver" << LL_ENDL; + drvinfo = gDXHardware.getDriverVersionWMI(LLDXHardware::GPU_ANY); + } + if (!drvinfo.empty()) { info["GRAPHICS_DRIVER_VERSION"] = drvinfo; @@ -4810,13 +4842,18 @@ void LLAppViewer::idle() } } + + // Update layonts, handle mouse events, tooltips, e t c + // updateUI() needs to be called even in case viewer disconected + // since related notification still needs handling and allows + // opening chat. + gViewerWindow->updateUI(); + if (gDisconnected) { return; } - gViewerWindow->updateUI(); - if (gTeleportDisplay) { return; diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 68c04d450b..7ab21f35cd 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -106,6 +106,7 @@ public: bool logoutRequestSent() { return mLogoutRequestSent; } bool isSecondInstance() { return mSecondInstance; } bool isUpdaterMissing(); // In use by tests + bool waitForUpdater(); void writeDebugInfo(bool isStatic=true); diff --git a/indra/newview/llaudiosourcevo.cpp b/indra/newview/llaudiosourcevo.cpp index 4b6c855bde..1846238d93 100644 --- a/indra/newview/llaudiosourcevo.cpp +++ b/indra/newview/llaudiosourcevo.cpp @@ -34,6 +34,7 @@ #include "llmutelist.h" #include "llviewercontrol.h" #include "llviewerparcelmgr.h" +#include "llvoavatarself.h" LLAudioSourceVO::LLAudioSourceVO(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, LLViewerObject *objectp) : LLAudioSource(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX), @@ -141,11 +142,36 @@ void LLAudioSourceVO::updateMute() LLVector3d pos_global = getPosGlobal(); F32 cutoff = mObjectp->getSoundCutOffRadius(); - if ((cutoff > 0.1f && !isInCutOffRadius(pos_global, cutoff)) // consider cutoff below 0.1m as off - || !LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) - { - mute = true; - } + // Object can specify radius at which it turns off + // consider cutoff below 0.1m as 'cutoff off' + if (cutoff > 0.1f && !isInCutOffRadius(pos_global, cutoff)) + { + mute = true; + } + // check if parcel allows sounds to pass border + else if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) + { + if (isAgentAvatarValid() && gAgentAvatarp->getParent()) + { + // Check if agent is riding this object + // Agent can ride something out of region border and canHearSound + // will treat object as not being part of agent's parcel. + LLViewerObject *sound_root = (LLViewerObject*)mObjectp->getRoot(); + LLViewerObject *agent_root = (LLViewerObject*)gAgentAvatarp->getRoot(); + if (sound_root != agent_root) + { + mute = true; + } + else + { + LL_INFOS() << "roots identical" << LL_ENDL; + } + } + else + { + mute = true; + } + } if (!mute) { diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index cdf82c77c1..bdd516e1de 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -558,9 +558,15 @@ public: mTimeBoxTextBox = getChild<LLTextBox>("time_box"); mInfoCtrl = LLUICtrlFactory::getInstance()->createFromFile<LLUICtrl>("inspector_info_ctrl.xml", this, LLPanel::child_registry_t::instance()); - llassert(mInfoCtrl != NULL); - mInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, mInfoCtrl)); - mInfoCtrl->setVisible(FALSE); + if (mInfoCtrl) + { + mInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, mInfoCtrl)); + mInfoCtrl->setVisible(FALSE); + } + else + { + LL_ERRS() << "Failed to create an interface element due to missing or corrupted file inspector_info_ctrl.xml" << LL_ENDL; + } return LLPanel::postBuild(); } diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 4a87273372..d4d4f641cf 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -610,6 +610,7 @@ LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLV S32 face, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, @@ -627,7 +628,7 @@ LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLV { LLVector4a local_end = end; LLVector4a local_intersection; - if (mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) + if (mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, pick_unselectable, face_hit, &local_intersection, tex_coord, normal, tangent)) { local_end = local_intersection; if (intersection) @@ -644,7 +645,7 @@ LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLV for (std::vector<LLVOVolume*>::iterator vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it) { LLVOVolume *volp = *vol_it; - if (mRootVolp != volp && volp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) + if (mRootVolp != volp && volp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, pick_unselectable, face_hit, &local_intersection, tex_coord, normal, tangent)) { local_end = local_intersection; if (intersection) diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h index 8e87299f3e..ea91d70e69 100644 --- a/indra/newview/llcontrolavatar.h +++ b/indra/newview/llcontrolavatar.h @@ -68,6 +68,7 @@ public: S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, // which face was hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 20fa6d490b..48c7df40df 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -272,9 +272,9 @@ BOOL LLConversationViewSession::postBuild() default: break; } - } - refresh(); + refresh(); // requires vmi + } return TRUE; } @@ -490,17 +490,20 @@ void LLConversationViewSession::refresh() { // Refresh the session view from its model data LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem()); - vmi->resetRefresh(); + if (vmi) + { + vmi->resetRefresh(); - if (mSessionTitle) - { - if (!highlightFriendTitle(vmi)) - { - LLStyle::Params title_style; - title_style.color = LLUIColorTable::instance().getColor("LabelTextColor"); - mSessionTitle->setText(vmi->getDisplayName(), title_style); - } - } + if (mSessionTitle) + { + if (!highlightFriendTitle(vmi)) + { + LLStyle::Params title_style; + title_style.color = LLUIColorTable::instance().getColor("LabelTextColor"); + mSessionTitle->setText(vmi->getDisplayName(), title_style); + } + } + } // Update all speaking indicators LLSpeakingIndicatorManager::updateSpeakingIndicators(); @@ -524,8 +527,11 @@ void LLConversationViewSession::refresh() } requestArrange(); - // Do the regular upstream refresh - LLFolderViewFolder::refresh(); + if (vmi) + { + // Do the regular upstream refresh + LLFolderViewFolder::refresh(); + } } void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& session_id) @@ -627,8 +633,11 @@ BOOL LLConversationViewParticipant::postBuild() } updateChildren(); - LLFolderViewItem::postBuild(); - refresh(); + if (getViewModelItem()) + { + LLFolderViewItem::postBuild(); + refresh(); + } return TRUE; } @@ -712,10 +721,10 @@ void LLConversationViewParticipant::refresh() // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted()); + + // Do the regular upstream refresh + LLFolderViewItem::refresh(); } - - // Do the regular upstream refresh - LLFolderViewItem::refresh(); } void LLConversationViewParticipant::addToFolder(LLFolderViewFolder* folder) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 4a0c9d399f..bfb79f3a4c 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -249,12 +249,9 @@ void LLDrawable::cleanupReferences() { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; - std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); mFaces.clear(); - gObjectList.removeDrawable(this); - gPipeline.unlinkDrawable(this); removeFromOctree(); diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index a3837fe10c..1e548141c8 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -37,6 +37,7 @@ #include "lldrawpoolbump.h" #include "lldrawpoolmaterials.h" #include "lldrawpoolground.h" +#include "lldrawpoolpbropaque.h" #include "lldrawpoolsimple.h" #include "lldrawpoolsky.h" #include "lldrawpooltree.h" @@ -117,6 +118,9 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0) case POOL_WL_SKY: poolp = new LLDrawPoolWLSky(); break; + case POOL_PBR_OPAQUE: + poolp = new LLDrawPoolPBROpaque(); + break; default: LL_ERRS() << "Unknown draw pool type!" << LL_ENDL; return NULL; diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index fd1b022e5b..f7fc2d2061 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -48,6 +48,7 @@ public: enum { // Correspond to LLPipeline render type + // NOTE: Keep in sync with gPoolNames POOL_SIMPLE = 1, POOL_GROUND, POOL_FULLBRIGHT, @@ -67,6 +68,7 @@ public: POOL_WATER, POOL_GLOW, POOL_ALPHA, + POOL_PBR_OPAQUE, NUM_POOL_TYPES, // * invisiprims work by rendering to the depth buffer but not the color buffer, occluding anything rendered after them // - and the LLDrawPool types enum controls what order things are rendered in @@ -129,6 +131,7 @@ class LLRenderPass : public LLDrawPool public: // list of possible LLRenderPass types to assign a render batch to // NOTE: "rigged" variant MUST be non-rigged variant + 1 + // see LLVolumeGeometryManager::registerFace() enum { PASS_SIMPLE = NUM_POOL_TYPES, @@ -190,6 +193,8 @@ public: PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, PASS_ALPHA_INVISIBLE, PASS_ALPHA_INVISIBLE_RIGGED, + PASS_PBR_OPAQUE, + PASS_PBR_OPAQUE_RIGGED, NUM_RENDER_TYPES, }; diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index e674707c01..89b8ec1ba2 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -129,6 +129,8 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d } } +extern BOOL gCubeSnapshot; + void LLDrawPoolAlpha::renderPostDeferred(S32 pass) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; @@ -155,13 +157,13 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) forwardRender(); // final pass, render to depth for depth of field effects - if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField")) + if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot) { //update depth buffer sampler - gPipeline.mScreen.flush(); - gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(), - 0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); - gPipeline.mDeferredDepth.bindTarget(); + gPipeline.mRT->screen.flush(); + gPipeline.mRT->deferredDepth.copyContents(gPipeline.mRT->deferredScreen, 0, 0, gPipeline.mRT->deferredScreen.getWidth(), gPipeline.mRT->deferredScreen.getHeight(), + 0, 0, gPipeline.mRT->deferredDepth.getWidth(), gPipeline.mRT->deferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + gPipeline.mRT->deferredDepth.bindTarget(); simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram; simple_shader->bind(); @@ -175,8 +177,8 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, true); // <--- discard mostly transparent faces - gPipeline.mDeferredDepth.flush(); - gPipeline.mScreen.bindTarget(); + gPipeline.mRT->deferredDepth.flush(); + gPipeline.mRT->screen.bindTarget(); gGL.setColorMask(true, false); } diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 8db6a10e26..33ac91f88b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -465,6 +465,11 @@ void LLDrawPoolBump::beginFullbrightShiny() shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); cube_map->setMatrix(1); + if (shader->mFeatures.hasReflectionProbes) + { + gPipeline.bindReflectionProbes(*shader); + } + // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for // the cube map in the one pass shiny shaders gGL.getTexUnit(1)->disable(); @@ -526,6 +531,10 @@ void LLDrawPoolBump::endFullbrightShiny() { cube_map->disable(); cube_map->restoreMatrix(); + if (shader->mFeatures.hasReflectionProbes) + { + gPipeline.unbindReflectionProbes(*shader); + } shader->unbind(); } @@ -673,6 +682,7 @@ void LLDrawPoolBump::endBump(U32 pass) S32 LLDrawPoolBump::getNumDeferredPasses() { +#if 0 //DEPRECATED -- RenderObjectBump should always be TRUE if (gSavedSettings.getBOOL("RenderObjectBump")) { return 1; @@ -681,6 +691,9 @@ S32 LLDrawPoolBump::getNumDeferredPasses() { return 0; } +#else + return 1; +#endif } void LLDrawPoolBump::renderDeferred(S32 pass) @@ -741,6 +754,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass) void LLDrawPoolBump::renderPostDeferred(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL for (int i = 0; i < 2; ++i) { // two passes -- static and rigged mRigged = (i == 1); diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp new file mode 100644 index 0000000000..3930e11cf3 --- /dev/null +++ b/indra/newview/lldrawpoolpbropaque.cpp @@ -0,0 +1,158 @@ +/** + * @file lldrawpoolpbropaque.cpp + * @brief LLDrawPoolPBROpaque class implementation + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 "llviewerprecompiledheaders.h" + +#include "lldrawpool.h" +#include "lldrawpoolpbropaque.h" +#include "llviewershadermgr.h" +#include "pipeline.h" + +LLDrawPoolPBROpaque::LLDrawPoolPBROpaque() : + LLRenderPass(POOL_PBR_OPAQUE) +{ +} + +void LLDrawPoolPBROpaque::prerender() +{ + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); +} + +// Forward +void LLDrawPoolPBROpaque::beginRenderPass(S32 pass) +{ +} + +void LLDrawPoolPBROpaque::endRenderPass( S32 pass ) +{ +} + +void LLDrawPoolPBROpaque::render(S32 pass) +{ +} + +void LLDrawPoolPBROpaque::renderDeferred(S32 pass) +{ + if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_MATERIALS)) + { + return; + } + + const U32 type = LLPipeline::RENDER_TYPE_PASS_PBR_OPAQUE; + if (!gPipeline.hasRenderType(type)) + { + return; + } + + gGL.flush(); + + LLGLDisable blend(GL_BLEND); + LLGLDisable alpha_test(GL_ALPHA_TEST); + + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + + for (int i = 0; i < 2; ++i) + { + bool rigged = (i == 1); + LLGLSLShader* shader = &gDeferredPBROpaqueProgram; + U32 vertex_data_mask = getVertexDataMask(); + + if (rigged) + { + shader = shader->mRiggedVariant; + vertex_data_mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + shader->bind(); + + LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type+i); + LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type+i); + + for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) + { + LLDrawInfo* pparams = *i; + + if (pparams->mTexture.notNull()) + { + gGL.getTexUnit(0)->bindFast(pparams->mTexture); // diffuse + } + else + { + gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sWhiteImagep); + } + + if (pparams->mNormalMap) + { + shader->bindTexture(LLShaderMgr::BUMP_MAP, pparams->mNormalMap); + } + else + { + shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); + } + + if (pparams->mSpecularMap) + { + shader->bindTexture(LLShaderMgr::SPECULAR_MAP, pparams->mSpecularMap); // PBR linear packed Occlusion, Roughness, Metal. + } + else + { + shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); + } + + if (pparams->mEmissiveMap) + { + shader->bindTexture(LLShaderMgr::EMISSIVE_MAP, pparams->mEmissiveMap); // PBR sRGB Emissive + } + else + { + shader->bindTexture(LLShaderMgr::EMISSIVE_MAP, LLViewerFetchedTexture::sWhiteImagep); + } + + shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, pparams->mGLTFMaterial->mRoughnessFactor); + shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, pparams->mGLTFMaterial->mMetallicFactor); + shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, pparams->mGLTFMaterial->mEmissiveColor.mV); + + if (rigged) + { + if (pparams->mAvatar.notNull() && (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)) + { + uploadMatrixPalette(*pparams); + lastAvatar = pparams->mAvatar; + lastMeshId = pparams->mSkinInfo->mHash; + } + + pushBatch(*pparams, vertex_data_mask, FALSE, FALSE); + } + else + { + pushBatch(*pparams, vertex_data_mask, FALSE, FALSE); + } + } + } + + LLGLSLShader::sCurBoundShaderPtr->unbind(); +} diff --git a/indra/newview/lldrawpoolpbropaque.h b/indra/newview/lldrawpoolpbropaque.h new file mode 100644 index 0000000000..c355b10b12 --- /dev/null +++ b/indra/newview/lldrawpoolpbropaque.h @@ -0,0 +1,63 @@ +/** + * @file lldrawpoolpbropaque.h + * @brief LLDrawPoolPBrOpaque class definition + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDRAWPOOLPBROPAQUE_H +#define LL_LLDRAWPOOLPBROPAQUE_H + +#include "lldrawpool.h" + +class LLDrawPoolPBROpaque : public LLRenderPass +{ +public: + enum + { + // See: DEFERRED_VB_MASK + VERTEX_DATA_MASK = 0 + | LLVertexBuffer::MAP_VERTEX + | LLVertexBuffer::MAP_NORMAL + | LLVertexBuffer::MAP_TEXCOORD0 // Diffuse + | LLVertexBuffer::MAP_TEXCOORD1 // Normal + | LLVertexBuffer::MAP_TEXCOORD2 // Spec <-- ORM Occlusion Roughness Metal + | LLVertexBuffer::MAP_TANGENT + | LLVertexBuffer::MAP_COLOR + }; + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + + LLDrawPoolPBROpaque(); + + /*virtual*/ S32 getNumDeferredPasses() { return 1; } + /*virtual*/ void renderDeferred(S32 pass); + + // Non ALM isn't supported + /*virtual*/ void beginRenderPass(S32 pass); + /*virtual*/ void endRenderPass(S32 pass); + /*virtual*/ S32 getNumPasses() { return 0; } + /*virtual*/ void render(S32 pass = 0); + /*virtual*/ void prerender(); + +}; + +#endif // LL_LLDRAWPOOLPBROPAQUE_H diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 740396178b..52aacb607c 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -64,7 +64,6 @@ #pragma GCC diagnostic ignored "-Wuninitialized" #endif -extern BOOL gGLDebugLoggingEnabled; #define LL_MAX_INDICES_COUNT 1000000 static LLStaticHashedString sTextureIndexIn("texture_index_in"); @@ -587,7 +586,6 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) glTexCoordPointer(2, GL_FLOAT, 8, vol_face.mTexCoords); } gGL.syncMatrices(); - LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x00FF00 ); glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } @@ -1034,12 +1032,12 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po { const LLMatrix4& vol_mat = getWorldMatrix(); const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset); - const LLVector4a& normal4a = vf.mNormals[0]; - const LLVector4a& tangent = vf.mTangents[0]; - if (!&tangent) + if (! (vf.mNormals && vf.mTangents)) { return; } + const LLVector4a& normal4a = *vf.mNormals; + const LLVector4a& tangent = *vf.mTangents; LLVector4a binormal4a; binormal4a.setCross3(normal4a, tangent); @@ -1385,6 +1383,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLColor4U color = tep->getColor(); + if (tep->getGLTFMaterial()) + { + color = tep->getGLTFMaterial()->mAlbedoColor; + } + if (rebuild_color) { //decide if shiny goes in alpha channel of color if (tep && @@ -1542,7 +1545,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, !rebuild_weights && //TODO: add support for weights !volume.isUnique()) //source volume is NOT flexi { //use transform feedback to pack vertex buffer - //gGLDebugLoggingEnabled = TRUE; LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - transform feedback"); LLGLEnable discard(GL_RASTERIZER_DISCARD); @@ -1795,10 +1797,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, scalea.load3(scale.mV); LLMaterial* mat = tep->getMaterialParams().get(); + LLGLTFMaterial* gltf_mat = tep->getGLTFMaterial(); bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - if (mat && !do_bump) + if ((mat || gltf_mat) && !do_bump) { do_bump = mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1) || mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2); @@ -2024,10 +2027,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mVertexBuffer->flush(); } - if (!mat && do_bump) + if ((!mat && !gltf_mat) && do_bump) { mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount, map_range); + mVObjp->getVolume()->genTangents(f); + for (S32 i = 0; i < num_vertices; i++) { LLVector4a tangent = vf.mTangents[i]; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index c13b63433c..a02bb56489 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -772,6 +772,14 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) } LLFavoritesOrderStorage::instance().mPrevFavorites = mItems; mGetPrevItems = false; + + if (LLFavoritesOrderStorage::instance().isStorageUpdateNeeded()) + { + if (!mItemsChangedTimer.getStarted()) + { + mItemsChangedTimer.start(); + } + } } const LLButton::Params& button_params = getButtonParams(); @@ -1606,7 +1614,7 @@ void LLFavoritesOrderStorage::destroyClass() file.close(); LLFile::remove(filename); } - if(mSaveOnExit) + if(mSaveOnExit || gSavedSettings.getBOOL("UpdateRememberPasswordSetting")) { LLFavoritesOrderStorage::instance().saveFavoritesRecord(true); } @@ -1650,7 +1658,6 @@ void LLFavoritesOrderStorage::load() llifstream in_file; in_file.open(filename.c_str()); LLSD fav_llsd; - LLSD user_llsd; if (in_file.is_open()) { LLSDSerialize::fromXML(fav_llsd, in_file); @@ -1660,12 +1667,12 @@ void LLFavoritesOrderStorage::load() in_file.close(); if (fav_llsd.isMap() && fav_llsd.has(gAgentUsername)) { - user_llsd = fav_llsd[gAgentUsername]; + mStorageFavorites = fav_llsd[gAgentUsername]; S32 index = 0; bool needs_validation = gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); - for (LLSD::array_iterator iter = user_llsd.beginArray(); - iter != user_llsd.endArray(); ++iter) + for (LLSD::array_iterator iter = mStorageFavorites.beginArray(); + iter != mStorageFavorites.endArray(); ++iter) { // Validation LLUUID fv_id = iter->get("id").asUUID(); @@ -1967,7 +1974,7 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) } } - if((items != mPrevFavorites) || name_changed || pref_changed) + if((items != mPrevFavorites) || name_changed || pref_changed || gSavedSettings.getBOOL("UpdateRememberPasswordSetting")) { std::string filename = getStoredFavoritesFilename(); if (!filename.empty()) @@ -1988,6 +1995,12 @@ BOOL LLFavoritesOrderStorage::saveFavoritesRecord(bool pref_changed) LLSD user_llsd; S32 fav_iter = 0; mMissingSLURLs.clear(); + + LLSD save_pass; + save_pass["save_password"] = gSavedSettings.getBOOL("RememberPassword"); + user_llsd[fav_iter] = save_pass; + fav_iter++; + for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) { LLSD value; @@ -2058,6 +2071,23 @@ void LLFavoritesOrderStorage::showFavoritesOnLoginChanged(BOOL show) } } +bool LLFavoritesOrderStorage::isStorageUpdateNeeded() +{ + if (!mRecreateFavoriteStorage) + { + for (LLSD::array_iterator iter = mStorageFavorites.beginArray(); + iter != mStorageFavorites.endArray(); ++iter) + { + if (mFavoriteNames[iter->get("id").asUUID()] != iter->get("name").asString()) + { + mRecreateFavoriteStorage = true; + return true; + } + } + } + return false; +} + void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) { if (mTargetLandmarkId.isNull()) return; diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index 2d7ba9df67..3b439b31fd 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -226,8 +226,11 @@ public: BOOL saveFavoritesRecord(bool pref_changed = false); void showFavoritesOnLoginChanged(BOOL show); - LLInventoryModel::item_array_t mPrevFavorites; + bool isStorageUpdateNeeded(); + LLInventoryModel::item_array_t mPrevFavorites; + LLSD mStorageFavorites; + bool mRecreateFavoriteStorage; const static S32 NO_INDEX; static bool mSaveOnExit; @@ -254,7 +257,6 @@ private: slurls_map_t mSLURLs; std::set<LLUUID> mMissingSLURLs; bool mIsDirty; - bool mRecreateFavoriteStorage; struct IsNotInFavorites { diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 3669fb1eeb..1dd9a43b72 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -55,13 +55,13 @@ LLFilePicker LLFilePicker::sInstance; #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" #define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0" #define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0" -#ifdef _CORY_TESTING -#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" -#endif +#define GLTF_FILTER L"glTF (*.gltf; *.glb)\0*.gltf;*.glb\0" #define XML_FILTER L"XML files (*.xml)\0*.xml\0" #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0" #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" #define MODEL_FILTER L"Model files (*.dae)\0*.dae\0" +#define MATERIAL_FILTER L"GLTF Files (*.gltf; *.glb)\0*.gltf;*.glb\0" +#define MATERIAL_TEXTURES_FILTER L"GLTF Import (*.gltf; *.glb; *.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.gltf;*.glb;*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" #define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0" #define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0" #endif @@ -193,16 +193,14 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = ANIM_FILTER \ L"\0"; break; - case FFLOAD_COLLADA: + case FFLOAD_GLTF: + mOFN.lpstrFilter = GLTF_FILTER \ + L"\0"; + break; + case FFLOAD_COLLADA: mOFN.lpstrFilter = COLLADA_FILTER \ L"\0"; break; -#ifdef _CORY_TESTING - case FFLOAD_GEOMETRY: - mOFN.lpstrFilter = GEOMETRY_FILTER \ - L"\0"; - break; -#endif case FFLOAD_XML: mOFN.lpstrFilter = XML_FILTER \ L"\0"; @@ -219,6 +217,16 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = MODEL_FILTER \ L"\0"; break; + case FFLOAD_MATERIAL: + mOFN.lpstrFilter = MATERIAL_FILTER \ + L"\0"; + break; + case FFLOAD_MATERIAL_TEXTURE: + mOFN.lpstrFilter = MATERIAL_TEXTURES_FILTER \ + MATERIAL_FILTER \ + IMAGE_FILTER \ + L"\0"; + break; case FFLOAD_SCRIPT: mOFN.lpstrFilter = SCRIPT_FILTER \ L"\0"; @@ -480,18 +488,16 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename, L"XAF Anim File (*.xaf)\0*.xaf\0" \ L"\0"; break; -#ifdef _CORY_TESTING - case FFSAVE_GEOMETRY: + case FFSAVE_GLTF: if (filename.empty()) { - wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ } - mOFN.lpstrDefExt = L"slg"; + mOFN.lpstrDefExt = L"glb"; mOFN.lpstrFilter = - L"SLG SL Geometry File (*.slg)\0*.slg\0" \ + L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \ L"\0"; break; -#endif case FFSAVE_XML: if (filename.empty()) { @@ -621,14 +627,13 @@ std::vector<std::string>* LLFilePicker::navOpenFilterProc(ELoadFilter filter) // allowedv->push_back("bvh"); allowedv->push_back("anim"); break; + case FFLOAD_GLTF: + allowedv->push_back("gltf"); + allowedv->push_back("glb"); + break; case FFLOAD_COLLADA: allowedv->push_back("dae"); break; -#ifdef _CORY_TESTING - case FFLOAD_GEOMETRY: - allowedv->push_back("slg"); - break; -#endif case FFLOAD_XML: allowedv->push_back("xml"); break; @@ -728,13 +733,11 @@ bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena extension = "xaf"; break; -#ifdef _CORY_TESTING - case FFSAVE_GEOMETRY: + case FFSAVE_GLTF: type = "\?\?\?\?"; creator = "\?\?\?\?"; - extension = "slg"; + extension = "glb"; break; -#endif case FFSAVE_XML: type = "\?\?\?\?"; @@ -1354,10 +1357,13 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) case FFLOAD_XML: filtername = add_xml_filter_to_gtkchooser(picker); break; - case FFLOAD_COLLADA: - filtername = add_collada_filter_to_gtkchooser(picker); - break; - case FFLOAD_IMAGE: + case FFLOAD_GLTF: + filtername = dead_code_should_blow_up_here(picker); + break; + case FFLOAD_COLLADA: + filtername = add_collada_filter_to_gtkchooser(picker); + break; + case FFLOAD_IMAGE: filtername = add_imageload_filter_to_gtkchooser(picker); break; case FFLOAD_SCRIPT: diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 04ba4416d7..a03f3f6711 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -77,9 +77,7 @@ public: FFLOAD_WAV = 2, FFLOAD_IMAGE = 3, FFLOAD_ANIM = 4, -#ifdef _CORY_TESTING - FFLOAD_GEOMETRY = 5, -#endif + FFLOAD_GLTF = 5, FFLOAD_XML = 6, FFLOAD_SLOBJECT = 7, FFLOAD_RAW = 8, @@ -88,7 +86,9 @@ public: FFLOAD_SCRIPT = 11, FFLOAD_DICTIONARY = 12, FFLOAD_DIRECTORY = 13, // To call from lldirpicker. - FFLOAD_EXE = 14 // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin + FFLOAD_EXE = 14, // Note: EXE will be treated as ALL on Windows and Linux but not on Darwin + FFLOAD_MATERIAL = 15, + FFLOAD_MATERIAL_TEXTURE = 16, }; enum ESaveFilter @@ -99,9 +99,7 @@ public: FFSAVE_BMP = 5, FFSAVE_AVI = 6, FFSAVE_ANIM = 7, -#ifdef _CORY_TESTING - FFSAVE_GEOMETRY = 8, -#endif + FFSAVE_GLTF = 8, FFSAVE_XML = 9, FFSAVE_COLLADA = 10, FFSAVE_RAW = 11, diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 4f3c2d8d34..d5115df35f 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -386,7 +386,8 @@ void LLVolumeImplFlexible::doIdleUpdate() U64 throttling_delay = (virtual_frame_num + id) % update_period; if ((throttling_delay == 0 && mLastFrameNum < virtual_frame_num) //one or more virtual frames per frame - || (mLastFrameNum + update_period < virtual_frame_num)) // missed virtual frame + || (mLastFrameNum + update_period < virtual_frame_num) // missed virtual frame + || mLastFrameNum > virtual_frame_num) // overflow { // We need mLastFrameNum to compensate for 'unreliable time' and to filter 'duplicate' frames // If happened too late, subtract throttling_delay (it is zero otherwise) @@ -787,10 +788,7 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) volume->updateRelativeXform(); - if (mRenderRes > -1) - { - doFlexibleUpdate(); - } + doFlexibleUpdate(); // Object may have been rotated, which means it needs a rebuild. See SL-47220 BOOL rotated = FALSE; diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp index ec05ba924c..0964daa4d5 100644 --- a/indra/newview/llfloaterautoreplacesettings.cpp +++ b/indra/newview/llfloaterautoreplacesettings.cpp @@ -350,7 +350,7 @@ void LLFloaterAutoReplaceSettings::onDeleteEntry() // called when the Import List button is pressed void LLFloaterAutoReplaceSettings::onImportList() { - (new LLFilePickerReplyThread(boost::bind(&LLFloaterAutoReplaceSettings::loadListFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterAutoReplaceSettings::loadListFromFile, this, _1), LLFilePicker::FFLOAD_XML, false); } void LLFloaterAutoReplaceSettings::loadListFromFile(const std::vector<std::string>& filenames) @@ -537,7 +537,7 @@ void LLFloaterAutoReplaceSettings::onExportList() { std::string listName=mListNames->getFirstSelected()->getColumn(0)->getValue().asString(); std::string listFileName = listName + ".xml"; - (new LLFilePickerReplyThread(boost::bind(&LLFloaterAutoReplaceSettings::saveListToFile, this, _1, listName), LLFilePicker::FFSAVE_XML, listFileName))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterAutoReplaceSettings::saveListToFile, this, _1, listName), LLFilePicker::FFSAVE_XML, listFileName); } void LLFloaterAutoReplaceSettings::saveListToFile(const std::vector<std::string>& filenames, std::string listName) diff --git a/indra/newview/llfloaterbulkpermission.cpp b/indra/newview/llfloaterbulkpermission.cpp index a1a06706bc..a3cc939f85 100644 --- a/indra/newview/llfloaterbulkpermission.cpp +++ b/indra/newview/llfloaterbulkpermission.cpp @@ -306,6 +306,7 @@ void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, LLInve ( asstype == LLAssetType::AT_LSL_TEXT && gSavedSettings.getBOOL("BulkChangeIncludeScripts" )) || ( asstype == LLAssetType::AT_SOUND && gSavedSettings.getBOOL("BulkChangeIncludeSounds" )) || ( asstype == LLAssetType::AT_SETTINGS && gSavedSettings.getBOOL("BulkChangeIncludeSettings" )) || + ( asstype == LLAssetType::AT_MATERIAL && gSavedSettings.getBOOL("BulkChangeIncludeMaterials")) || ( asstype == LLAssetType::AT_TEXTURE && gSavedSettings.getBOOL("BulkChangeIncludeTextures" ))) { LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp index 24673d5a7c..a6a825500d 100644 --- a/indra/newview/llfloatereditextdaycycle.cpp +++ b/indra/newview/llfloatereditextdaycycle.cpp @@ -1523,7 +1523,7 @@ bool LLFloaterEditExtDayCycle::isAddingFrameAllowed() void LLFloaterEditExtDayCycle::doImportFromDisk() { // Load a a legacy Windlight XML from disk. - (new LLFilePickerReplyThread(boost::bind(&LLFloaterEditExtDayCycle::loadSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterEditExtDayCycle::loadSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false); } void LLFloaterEditExtDayCycle::loadSettingFromFile(const std::vector<std::string>& filenames) diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp index a6640cc073..a3504ac6ee 100644 --- a/indra/newview/llfloaterevent.cpp +++ b/indra/newview/llfloaterevent.cpp @@ -108,11 +108,12 @@ void LLFloaterEvent::setEventID(const U32 event_id) LLSD subs; subs["EVENT_ID"] = (S32)event_id; // get the search URL and expand all of the substitutions - // (also adds things like [LANGUAGE], [VERSION], [OS], etc.) - std::ostringstream url; - url << gSavedSettings.getString("EventURL") << event_id << std::endl; + // (also adds things like [LANGUAGE], [VERSION], [OS], etc.) + + std::string expanded_url = LLWeb::expandURLSubstitutions(gSavedSettings.getString("EventURL"), subs); + // and load the URL in the web view - mBrowser->navigateTo(url.str()); + mBrowser->navigateTo(expanded_url); } } diff --git a/indra/newview/llfloaterfixedenvironment.cpp b/indra/newview/llfloaterfixedenvironment.cpp index fec218ca3b..68bb458e61 100644 --- a/indra/newview/llfloaterfixedenvironment.cpp +++ b/indra/newview/llfloaterfixedenvironment.cpp @@ -439,7 +439,7 @@ void LLFloaterFixedEnvironmentWater::onOpen(const LLSD& key) void LLFloaterFixedEnvironmentWater::doImportFromDisk() { // Load a a legacy Windlight XML from disk. - (new LLFilePickerReplyThread(boost::bind(&LLFloaterFixedEnvironmentWater::loadWaterSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterFixedEnvironmentWater::loadWaterSettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false); } void LLFloaterFixedEnvironmentWater::loadWaterSettingFromFile(const std::vector<std::string>& filenames) @@ -525,7 +525,7 @@ void LLFloaterFixedEnvironmentSky::onClose(bool app_quitting) void LLFloaterFixedEnvironmentSky::doImportFromDisk() { // Load a a legacy Windlight XML from disk. - (new LLFilePickerReplyThread(boost::bind(&LLFloaterFixedEnvironmentSky::loadSkySettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterFixedEnvironmentSky::loadSkySettingFromFile, this, _1), LLFilePicker::FFLOAD_XML, false); } void LLFloaterFixedEnvironmentSky::loadSkySettingFromFile(const std::vector<std::string>& filenames) diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 34499ac170..93a0b39e02 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -551,7 +551,7 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part void LLFloaterIMSessionTab::updateConversationViewParticipant(const LLUUID& participant_id) { LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id); - if (widget) + if (widget && widget->getViewModelItem()) { widget->refresh(); } @@ -576,8 +576,11 @@ void LLFloaterIMSessionTab::refreshConversation() { participants_uuids.push_back(widget_it->first); } - widget_it->second->refresh(); - widget_it->second->setVisible(TRUE); + if (widget_it->second->getViewModelItem()) + { + widget_it->second->refresh(); + widget_it->second->setVisible(TRUE); + } ++widget_it; } if (is_ad_hoc || mIsP2PChat) @@ -1126,7 +1129,10 @@ void LLFloaterIMSessionTab::getSelectedUUIDs(uuid_vec_t& selected_uuids) for (; it != it_end; ++it) { LLConversationItem* conversation_item = static_cast<LLConversationItem *>((*it)->getViewModelItem()); - selected_uuids.push_back(conversation_item->getUUID()); + if (conversation_item) + { + selected_uuids.push_back(conversation_item->getUUID()); + } } } diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index 93a26f31cc..558b14bba7 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -292,7 +292,7 @@ void LLFloaterJoystick::refreshListOfDevices() std::string desc = LLViewerJoystick::getInstance()->getDescription(); if (!desc.empty()) { - LLSD value = LLSD::Integer(0); + LLSD value = LLSD::Integer(1); // value for selection addDevice(desc, value); mHasDeviceList = true; } @@ -392,6 +392,9 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel) LLSD value = self->mJoysticksCombo->getValue(); bool joystick_enabled = true; + // value is 0 for no device, + // 1 for a device on Mac (single device, no list support yet) + // binary packed guid for a device on windows (can have multiple devices) if (value.isInteger()) { // ndof already has a device selected, we are just setting it enabled or disabled @@ -400,7 +403,7 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel) else { LLViewerJoystick::getInstance()->initDevice(value); - // else joystick is enabled, because combobox holds id of device + // else joystick is enabled, because combobox holds id of the device joystick_enabled = true; } gSavedSettings.setBOOL("JoystickEnabled", joystick_enabled); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 04133f2710..d78f80ad12 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -452,7 +452,8 @@ BOOL LLPanelLandGeneral::postBuild() mEditDesc = getChild<LLTextEditor>("Description"); mEditDesc->setCommitOnFocusLost(TRUE); - mEditDesc->setCommitCallback(onCommitAny, this); + mEditDesc->setCommitCallback(onCommitAny, this); + mEditDesc->setContentTrusted(false); // No prevalidate function - historically the prevalidate function was broken, // allowing residents to put in characters like U+2661 WHITE HEART SUIT, so // preserve that ability. @@ -749,6 +750,7 @@ void LLPanelLandGeneral::refresh() BOOL can_edit_identity = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_IDENTITY); mEditName->setEnabled(can_edit_identity); mEditDesc->setEnabled(can_edit_identity); + mEditDesc->setParseURLs(!can_edit_identity); BOOL can_edit_agent_only = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_NO_POWERS); mBtnSetGroup->setEnabled(can_edit_agent_only && !parcel->getIsGroupOwned()); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index fe5120376c..b7c98c915c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -97,7 +97,7 @@ private: }; LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) -: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) +: LLFilePickerThread(LLFilePicker::FFLOAD_MODEL) { mMP = mp; mLOD = lod; @@ -330,8 +330,8 @@ void LLFloaterModelPreview::initModelPreview() S32 tex_width = 512; S32 tex_height = 512; - S32 max_width = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mScreenWidth); - S32 max_height = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mScreenHeight); + S32 max_width = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mRT->width); + S32 max_height = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mRT->height); while ((tex_width << 1) < max_width) { @@ -741,7 +741,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) { case LLModelPreview::MESH_OPTIMIZER_AUTO: case LLModelPreview::MESH_OPTIMIZER_SLOPPY: - case LLModelPreview::MESH_OPTIMIZER_COMBINE: + case LLModelPreview::MESH_OPTIMIZER_PRECISE: mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode); break; default: @@ -1745,7 +1745,7 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) S32 index = lod_source_combo->getCurrentIndex(); if (index == LLModelPreview::MESH_OPTIMIZER_AUTO || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY - || index == LLModelPreview::MESH_OPTIMIZER_COMBINE) + || index == LLModelPreview::MESH_OPTIMIZER_PRECISE) { //rebuild LoD to update triangle counts onLODParamCommit(lod, true); } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 70114df989..34596d165b 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1180,30 +1180,10 @@ void LLFloaterPreference::buildPopupLists() void LLFloaterPreference::refreshEnabledState() { - LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); - LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); + LLCheckBoxCtrl* ctrl_pbr = getChild<LLCheckBoxCtrl>("UsePBRShaders"); - // if vertex shaders off, disable all shader related products - if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) - { - ctrl_wind_light->setEnabled(FALSE); - ctrl_wind_light->setValue(FALSE); - } - else - { - ctrl_wind_light->setEnabled(TRUE); - } - - //Deferred/SSAO/Shadows - BOOL bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump"); - BOOL shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); - BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - bumpshiny && - shaders && - gGLManager.mHasFramebufferObject && - (ctrl_wind_light->get()) ? TRUE : FALSE; - - ctrl_deferred->setEnabled(enabled); + //PBR + ctrl_pbr->setEnabled(TRUE); // Cannot have floater active until caps have been received getChild<LLButton>("default_creation_permissions")->setEnabled(LLStartUp::getStartupState() < STATE_STARTED ? false : true); @@ -1221,51 +1201,21 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() ctrl_reflections->setEnabled(reflections); reflections_text->setEnabled(reflections); - // Bump & Shiny - LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny"); - bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); - bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE); - - // Avatar Mode - // Avatar Render Mode - getChild<LLCheckBoxCtrl>("AvatarCloth")->setEnabled(TRUE); - - // Vertex Shaders, Global Shader Enable - // SL-12594 Basic shaders are always enabled. DJH TODO clean up now-orphaned state handling code - LLSliderCtrl* terrain_detail = getChild<LLSliderCtrl>("TerrainDetail"); // can be linked with control var - LLTextBox* terrain_text = getChild<LLTextBox>("TerrainDetailText"); - - terrain_detail->setEnabled(FALSE); - terrain_text->setEnabled(FALSE); - // WindLight - LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); - ctrl_wind_light->setEnabled(TRUE); sky->setEnabled(TRUE); sky_text->setEnabled(TRUE); - //Deferred/SSAO/Shadows - LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); - - BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) && - gGLManager.mHasFramebufferObject && - (ctrl_wind_light->get()) ? TRUE : FALSE; - ctrl_deferred->setEnabled(enabled); LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO"); LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF"); LLComboBox* ctrl_shadow = getChild<LLComboBox>("ShadowDetail"); LLTextBox* shadow_text = getChild<LLTextBox>("RenderShadowDetailText"); - // note, okay here to get from ctrl_deferred as it's twin, ctrl_deferred2 will alway match it - enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE); + BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO"); - ctrl_deferred->set(gSavedSettings.getBOOL("RenderDeferred")); - ctrl_ssao->setEnabled(enabled); ctrl_dof->setEnabled(enabled); @@ -1288,11 +1238,6 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() getChildView("texture compression")->setEnabled(FALSE); } - // if no windlight shaders, turn off nighttime brightness, gamma, and fog distance - LLUICtrl* gamma_ctrl = getChild<LLUICtrl>("gamma"); - gamma_ctrl->setEnabled(!gPipeline.canUseWindLightShaders()); - getChildView("(brightness, lower is brighter)")->setEnabled(!gPipeline.canUseWindLightShaders()); - getChildView("fog")->setEnabled(!gPipeline.canUseWindLightShaders()); getChildView("antialiasing restart")->setVisible(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")); // now turn off any features that are unavailable @@ -1345,59 +1290,11 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() { LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections"); LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText"); - LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth"); - LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); - LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); LLComboBox* ctrl_shadows = getChild<LLComboBox>("ShadowDetail"); LLTextBox* shadows_text = getChild<LLTextBox>("RenderShadowDetailText"); LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO"); - LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF"); - LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); - LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); - - // disabled windlight - if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) - { - ctrl_wind_light->setEnabled(FALSE); - ctrl_wind_light->setValue(FALSE); - - sky->setEnabled(FALSE); - sky_text->setEnabled(FALSE); - - //deferred needs windlight, disable deferred - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - - ctrl_deferred->setEnabled(FALSE); - ctrl_deferred->setValue(FALSE); - } - - // disabled deferred - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") || - !gGLManager.mHasFramebufferObject) - { - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - - ctrl_deferred->setEnabled(FALSE); - ctrl_deferred->setValue(FALSE); - } - // disabled deferred SSAO + // disabled deferred SSAO if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO")) { ctrl_ssao->setEnabled(FALSE); @@ -1419,13 +1316,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() ctrl_reflections->setValue(FALSE); reflections_text->setEnabled(FALSE); } - - // disabled cloth - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth")) - { - ctrl_avatar_cloth->setEnabled(FALSE); - ctrl_avatar_cloth->setValue(FALSE); - } } void LLFloaterPreference::refresh() diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 19080f05c0..296e155d28 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -2108,6 +2108,8 @@ bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region) LLTextBox* region_landtype = getChild<LLTextBox>("region_landtype_text"); region_landtype->setText(region->getLocalizedSimProductName()); + + getChild<LLButton>("reset_covenant")->setEnabled(gAgent.isGodlike() || (region && region->canManageEstate())); // let the parent class handle the general data collection. bool rv = LLPanelRegionInfo::refreshFromRegion(region); diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp index de5d59f484..32eb70cd39 100644 --- a/indra/newview/llfloaterspellchecksettings.cpp +++ b/indra/newview/llfloaterspellchecksettings.cpp @@ -259,7 +259,7 @@ BOOL LLFloaterSpellCheckerImport::postBuild(void) void LLFloaterSpellCheckerImport::onBtnBrowse() { - (new LLFilePickerReplyThread(boost::bind(&LLFloaterSpellCheckerImport::importSelectedDictionary, this, _1), LLFilePicker::FFLOAD_DICTIONARY, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterSpellCheckerImport::importSelectedDictionary, this, _1), LLFilePicker::FFLOAD_DICTIONARY, false); } void LLFloaterSpellCheckerImport::importSelectedDictionary(const std::vector<std::string>& filenames) diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 0429749e11..77a04bc5d7 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -480,30 +480,61 @@ void LLFloaterTools::refresh() else #endif { - F32 link_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost(); - S32 link_count = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount(); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + F32 link_cost = selection->getSelectedLinksetCost(); + S32 link_count = selection->getRootObjectCount(); + S32 object_count = selection->getObjectCount(); - LLCrossParcelFunctor func; - if (LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true)) - { - // Selection crosses parcel bounds. - // We don't display remaining land capacity in this case. - const LLStringExplicit empty_str(""); - childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", empty_str); - } - else - { - LLViewerObject* selected_object = mObjectSelection->getFirstObject(); - if (selected_object) - { - // Select a parcel at the currently selected object's position. - LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal()); - } - else - { - LL_WARNS() << "Failed to get selected object" << LL_ENDL; - } - } + LLCrossParcelFunctor func; + if (!LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true)) + { + // Unless multiple parcels selected, higlight parcel object is at. + LLViewerObject* selected_object = mObjectSelection->getFirstObject(); + if (selected_object) + { + // Select a parcel at the currently selected object's position. + LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal()); + } + else + { + LL_WARNS() << "Failed to get selected object" << LL_ENDL; + } + } + + if (object_count == 1) + { + // "selection_faces" shouldn't be visible if not LLToolFace::getInstance() + // But still need to be populated in case user switches + + std::string faces_str = ""; + + for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end();) + { + LLObjectSelection::iterator nextiter = iter++; // not strictly needed, we have only one object + LLSelectNode* node = *nextiter; + LLViewerObject* object = (*nextiter)->getObject(); + if (!object) + continue; + S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + if (!faces_str.empty()) + { + faces_str += ", "; + } + faces_str += llformat("%d", te); + } + } + } + + childSetTextArg("selection_faces", "[FACES_STRING]", faces_str); + } + + bool show_faces = (object_count == 1) + && LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + getChildView("selection_faces")->setVisible(show_faces); LLStringUtil::format_map_t selection_args; selection_args["OBJ_COUNT"] = llformat("%.1d", link_count); @@ -824,7 +855,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty(); getChildView("selection_count")->setVisible(!land_visible && have_selection); - getChildView("remaining_capacity")->setVisible(!land_visible && have_selection); + getChildView("selection_faces")->setVisible(LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool() + && LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1); getChildView("selection_empty")->setVisible(!land_visible && !have_selection); mTab->setVisible(!land_visible); @@ -1095,7 +1127,7 @@ void LLFloaterTools::onClickGridOptions() { LLFloater* floaterp = LLFloaterReg::showInstance("build_options"); // position floater next to build tools, not over - floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp)); + floaterp->setShape(gFloaterView->findNeighboringPosition(this, floaterp), true); } // static @@ -1181,26 +1213,6 @@ void LLFloaterTools::updateLandImpacts() return; } - S32 rezzed_prims = parcel->getSimWidePrimCount(); - S32 total_capacity = parcel->getSimWideMaxPrimCapacity(); - LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); - if (region) - { - S32 max_tasks_per_region = (S32)region->getMaxTasks(); - total_capacity = llmin(total_capacity, max_tasks_per_region); - } - std::string remaining_capacity_str = ""; - - bool show_mesh_cost = gMeshRepo.meshRezEnabled(); - if (show_mesh_cost) - { - LLStringUtil::format_map_t remaining_capacity_args; - remaining_capacity_args["LAND_CAPACITY"] = llformat("%d", total_capacity - rezzed_prims); - remaining_capacity_str = getString("status_remaining_capacity", remaining_capacity_args); - } - - childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", remaining_capacity_str); - // Update land impacts info in the weights floater LLFloaterObjectWeights* object_weights_floater = LLFloaterReg::findTypedInstance<LLFloaterObjectWeights>("object_weights"); if(object_weights_floater) diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index e67c79a3a0..67a205417e 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -1023,7 +1023,7 @@ void LLFloaterUIPreview::onClickEditFloater() void LLFloaterUIPreview::onClickBrowseForEditor() { // Let the user choose an executable through the file picker dialog box - (new LLFilePickerReplyThread(boost::bind(&LLFloaterUIPreview::getExecutablePath, this, _1), LLFilePicker::FFLOAD_EXE, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterUIPreview::getExecutablePath, this, _1), LLFilePicker::FFLOAD_EXE, false); } void LLFloaterUIPreview::getExecutablePath(const std::vector<std::string>& filenames) @@ -1077,7 +1077,7 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector<std::string>& filen void LLFloaterUIPreview::onClickBrowseForDiffs() { // create load dialog box - (new LLFilePickerReplyThread(boost::bind(&LLFloaterUIPreview::getDiffsFilePath, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLFloaterUIPreview::getDiffsFilePath, this, _1), LLFilePicker::FFLOAD_XML, false); } void LLFloaterUIPreview::getDiffsFilePath(const std::vector<std::string>& filenames) diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 2c84cd1f93..09235d8fb2 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -45,6 +45,7 @@ //#include "llfirstuse.h" #include "llfloaterreg.h" // getTypedInstance() #include "llfocusmgr.h" +#include "lliconctrl.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llinventorymodelbackgroundfetch.h" @@ -307,6 +308,8 @@ BOOL LLFloaterWorldMap::postBuild() mCurZoomVal = log(LLWorldMapView::sMapScale/256.f)/log(2.f); getChild<LLUICtrl>("zoom slider")->setValue(mCurZoomVal); + + getChild<LLPanel>("expand_btn_panel")->setMouseDownCallback(boost::bind(&LLFloaterWorldMap::onExpandCollapseBtn, this)); setDefaultBtn(NULL); @@ -1315,6 +1318,22 @@ void LLFloaterWorldMap::onCopySLURL() LLNotificationsUtil::add("CopySLURL", args); } +void LLFloaterWorldMap::onExpandCollapseBtn() +{ + LLLayoutStack* floater_stack = getChild<LLLayoutStack>("floater_map_stack"); + LLLayoutPanel* controls_panel = getChild<LLLayoutPanel>("controls_lp"); + + bool toggle_collapse = !controls_panel->isCollapsed(); + floater_stack->collapsePanel(controls_panel, toggle_collapse); + floater_stack->updateLayout(); + + std::string image_name = getString(toggle_collapse ? "expand_icon" : "collapse_icon"); + std::string tooltip = getString(toggle_collapse ? "expand_tooltip" : "collapse_tooltip"); + getChild<LLIconCtrl>("expand_collapse_icon")->setImage(LLUI::getUIImage(image_name)); + getChild<LLIconCtrl>("expand_collapse_icon")->setToolTip(tooltip); + getChild<LLPanel>("expand_btn_panel")->setToolTip(tooltip); +} + // protected void LLFloaterWorldMap::centerOnTarget(BOOL animate) { diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index 14a9c26fb9..fcb55e9666 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -130,6 +130,8 @@ protected: void onShowAgentBtn(); void onCopySLURL(); + void onExpandCollapseBtn(); + void centerOnTarget(BOOL animate); void updateLocation(); diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp new file mode 100644 index 0000000000..af00cdd05f --- /dev/null +++ b/indra/newview/llgltfmateriallist.cpp @@ -0,0 +1,123 @@ +/** + * @file llgltfmateriallist.cpp + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 "llviewerprecompiledheaders.h" + +#include "llgltfmateriallist.h" + +#include "llassetstorage.h" +#include "llfilesystem.h" +#include "llsdserialize.h" +#include "lltinygltfhelper.h" + +#include "tinygltf/tiny_gltf.h" +#include <strstream> + +LLGLTFMaterialList gGLTFMaterialList; + +LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id) +{ + List::iterator iter = mList.find(id); + if (iter == mList.end()) + { + LLGLTFMaterial* mat = new LLGLTFMaterial(); + mList[id] = mat; + + mat->ref(); + + gAssetStorage->getAssetData(id, LLAssetType::AT_MATERIAL, + [=](const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status) + { + if (status) + { + LL_WARNS() << "Error getting material asset data: " << LLAssetStorage::getErrorString(status) << " (" << status << ")" << LL_ENDL; + } + + LLFileSystem file(id, asset_type, LLFileSystem::READ); + + std::vector<char> buffer; + buffer.resize(file.getSize()); + file.read((U8*)&buffer[0], buffer.size()); + + LLSD asset; + + // read file into buffer + std::istrstream str(&buffer[0], buffer.size()); + + if (LLSDSerialize::deserialize(asset, str, buffer.size())) + { + if (asset.has("version") && asset["version"] == "1.0") + { + if (asset.has("type") && asset["type"].asString() == "GLTF 2.0") + { + if (asset.has("data") && asset["data"].isString()) + { + std::string data = asset["data"]; + + tinygltf::TinyGLTF gltf; + tinygltf::TinyGLTF loader; + std::string error_msg; + std::string warn_msg; + + tinygltf::Model model_in; + + if (loader.LoadASCIIFromString(&model_in, &error_msg, &warn_msg, data.c_str(), data.length(), "")) + { + LLTinyGLTFHelper::setFromModel(mat, model_in); + } + else + { + LL_WARNS() << "Failed to decode material asset: " << LL_ENDL; + LL_WARNS() << warn_msg << LL_ENDL; + LL_WARNS() << error_msg << LL_ENDL; + } + } + } + } + } + else + { + LL_WARNS() << "Failed to deserialize material LLSD" << LL_ENDL; + } + + mat->unref(); + }, nullptr); + + return mat; + } + + return iter->second; +} + +void LLGLTFMaterialList::addMaterial(const LLUUID& id, LLGLTFMaterial* material) +{ + mList[id] = material; +} + +void LLGLTFMaterialList::removeMaterial(const LLUUID& id) +{ + mList.erase(id); +} + diff --git a/indra/newview/app_settings/shaders/class3/deferred/avatarShadowF.glsl b/indra/newview/llgltfmateriallist.h index 48eefc7a73..49760504e6 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/avatarShadowF.glsl +++ b/indra/newview/llgltfmateriallist.h @@ -1,52 +1,51 @@ -/** - * @file avatarShadowF.glsl +/** + * @file llgltfmateriallist.h * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2007, Linden Research, Inc. - * + * Copyright (C) 2022, 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]*/ -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif +#pragma once -uniform sampler2D diffuseMap; +#include "llgltfmaterial.h" +#include "llpointer.h" -#if !defined(DEPTH_CLAMP) -VARYING vec4 post_pos; -#endif +#include <unordered_map> -VARYING vec4 pos; +class LLGLTFMaterialList +{ +public: + LLGLTFMaterialList() {} -vec4 computeMoments(float depth, float a); + typedef std::unordered_map<LLUUID, LLPointer<LLGLTFMaterial > > List; + List mList; -void main() -{ - frag_color = computeMoments(length(pos), 1.0); + LLGLTFMaterial* getMaterial(const LLUUID& id); + + void addMaterial(const LLUUID& id, LLGLTFMaterial* material); + void removeMaterial(const LLUUID& id); + +}; + +extern LLGLTFMaterialList gGLTFMaterialList; -#if !defined(DEPTH_CLAMP) - gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0); -#endif -} diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp index 85a878c4a2..60294f6a51 100644 --- a/indra/newview/llhudicon.cpp +++ b/indra/newview/llhudicon.cpp @@ -64,7 +64,6 @@ LLHUDIcon::icon_instance_t LLHUDIcon::sIconInstances; LLHUDIcon::LLHUDIcon(const U8 type) : LLHUDObject(type), mImagep(NULL), - mPickID(0), mScale(0.1f), mHidden(FALSE) { @@ -76,15 +75,11 @@ LLHUDIcon::~LLHUDIcon() mImagep = NULL; } -void LLHUDIcon::renderIcon(BOOL for_select) +void LLHUDIcon::render() { LLGLSUIDefault texture_state; LLGLDepthTest gls_depth(GL_TRUE); LLGLDisable gls_stencil(GL_STENCIL_TEST); - if (for_select) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } if (mHidden) return; @@ -116,7 +111,7 @@ void LLHUDIcon::renderIcon(BOOL for_select) mDistance = dist_vec(icon_position, camera->getOrigin()); - F32 alpha_factor = for_select ? 1.f : clamp_rescale(mDistance, DIST_START_FADE, DIST_END_FADE, 1.f, 0.f); + F32 alpha_factor = clamp_rescale(mDistance, DIST_START_FADE, DIST_END_FADE, 1.f, 0.f); LLVector3 x_pixel_vec; LLVector3 y_pixel_vec; @@ -150,13 +145,6 @@ void LLHUDIcon::renderIcon(BOOL for_select) LLVector3 upper_left = icon_position - (x_scale * 0.5f) + y_scale; LLVector3 upper_right = icon_position + (x_scale * 0.5f) + y_scale; - if (for_select) - { - // set color to unique color id for picking - LLColor4U coloru((U8)(mPickID >> 16), (U8)(mPickID >> 8), (U8)mPickID); - gGL.color4ubv(coloru.mV); - } - else { LLColor4 icon_color = LLColor4::white; icon_color.mV[VALPHA] = alpha_factor; @@ -198,11 +186,6 @@ void LLHUDIcon::markDead() LLHUDObject::markDead(); } -void LLHUDIcon::render() -{ - renderIcon(FALSE); -} - BOOL LLHUDIcon::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection) { if (mHidden) @@ -296,37 +279,6 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& } //static -S32 LLHUDIcon::generatePickIDs(S32 start_id, S32 step_size) -{ - S32 cur_id = start_id; - icon_instance_t::iterator icon_it; - - for(icon_it = sIconInstances.begin(); icon_it != sIconInstances.end(); ++icon_it) - { - (*icon_it)->mPickID = cur_id; - cur_id += step_size; - } - - return cur_id; -} - -//static -LLHUDIcon* LLHUDIcon::handlePick(S32 pick_id) -{ - icon_instance_t::iterator icon_it; - - for(icon_it = sIconInstances.begin(); icon_it != sIconInstances.end(); ++icon_it) - { - if (pick_id == (*icon_it)->mPickID) - { - return *icon_it; - } - } - - return NULL; -} - -//static LLHUDIcon* LLHUDIcon::lineSegmentIntersectAll(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection) { icon_instance_t::iterator icon_it; diff --git a/indra/newview/llhudicon.h b/indra/newview/llhudicon.h index e00a985ddc..7f452b5c36 100644 --- a/indra/newview/llhudicon.h +++ b/indra/newview/llhudicon.h @@ -56,8 +56,6 @@ public: void restartLifeTimer() { mLifeTimer.reset(); } - static S32 generatePickIDs(S32 start_id, S32 step_size); - static LLHUDIcon* handlePick(S32 pick_id); static LLHUDIcon* lineSegmentIntersectAll(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection); static void updateAll(); @@ -75,14 +73,11 @@ protected: LLHUDIcon(const U8 type); ~LLHUDIcon(); - void renderIcon(BOOL for_select); // common render code - private: LLPointer<LLViewerTexture> mImagep; LLFrameTimer mAnimTimer; LLFrameTimer mLifeTimer; F32 mDistance; - S32 mPickID; F32 mScale; BOOL mHidden; diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 10814ac076..f357899be0 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -348,7 +348,7 @@ void LLInspectAvatar::onClickMuteVolume() LLMuteList* mute_list = LLMuteList::getInstance(); bool is_muted = mute_list->isMuted(mAvatarID, LLMute::flagVoiceChat); - LLMute mute(mAvatarID, mAvatarName.getDisplayName(), LLMute::AGENT); + LLMute mute(mAvatarID, mAvatarName.getUserName(), LLMute::AGENT); if (!is_muted) { mute_list->add(mute, LLMute::flagVoiceChat); diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index f78a5cc64e..cb7031971b 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -28,16 +28,17 @@ #include "llinspectobject.h" // Viewer +#include "llagent.h" // To standup #include "llfloatersidepanelcontainer.h" #include "llinspect.h" #include "llmediaentry.h" -#include "llnotificationsutil.h" // *TODO: Eliminate, add LLNotificationsUtil wrapper #include "llselectmgr.h" #include "llslurl.h" #include "llviewermenu.h" // handle_object_touch(), handle_buy() #include "llviewermedia.h" #include "llviewermediafocus.h" #include "llviewerobjectlist.h" // to select the requested object +#include "llvoavatarself.h" // Linden libraries #include "llbutton.h" // setLabel(), not virtual! @@ -635,7 +636,31 @@ void LLInspectObject::onClickTouch() void LLInspectObject::onClickSit() { - handle_object_sit_or_stand(); + bool is_sitting = false; + if (mObjectSelection) + { + LLSelectNode* node = mObjectSelection->getFirstRootNode(); + if (node && node->mValid) + { + LLViewerObject* root_object = node->getObject(); + if (root_object + && isAgentAvatarValid() + && gAgentAvatarp->isSitting() + && gAgentAvatarp->getRoot() == root_object) + { + is_sitting = true; + } + } + } + + if (is_sitting) + { + gAgent.standUp(); + } + else + { + handle_object_sit(mObjectID); + } closeFloater(); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index a0de3a2af1..7abe48709b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -785,13 +785,29 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, if (obj) { - items.push_back(std::string("Copy Separator")); + if (obj->getType() != LLAssetType::AT_CATEGORY) + { + items.push_back(std::string("Copy Separator")); + } items.push_back(std::string("Copy")); if (!isItemCopyable()) { disabled_items.push_back(std::string("Copy")); } + if (isAgentInventory()) + { + items.push_back(std::string("New folder from selected")); + items.push_back(std::string("Subfolder Separator")); + std::set<LLUUID> selected_uuid_set = LLAvatarActions::getInventorySelectedUUIDs(); + uuid_vec_t ids; + std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids)); + if (!is_only_items_selected(ids) && !is_only_cats_selected(ids)) + { + disabled_items.push_back(std::string("New folder from selected")); + } + } + if (obj->getIsLinkType()) { items.push_back(std::string("Find Original")); @@ -878,7 +894,10 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } } - items.push_back(std::string("Paste Separator")); + if (obj->getType() != LLAssetType::AT_CATEGORY) + { + items.push_back(std::string("Paste Separator")); + } addDeleteContextMenuOptions(items, disabled_items); @@ -1420,6 +1439,14 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, new_listener = new LLSettingsBridge(inventory, root, uuid, LLSettingsType::fromInventoryFlags(flags)); break; + case LLAssetType::AT_MATERIAL: + if (inv_type != LLInventoryType::IT_MATERIAL) + { + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; + } + new_listener = new LLMaterialBridge(inventory, root, uuid); + break; + default: LL_INFOS_ONCE() << "Unhandled asset type (llassetstorage.h): " << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << LL_ENDL; @@ -4011,6 +4038,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items disabled_items.push_back(std::string("New Note")); disabled_items.push_back(std::string("New Settings")); disabled_items.push_back(std::string("New Gesture")); + disabled_items.push_back(std::string("New Material")); disabled_items.push_back(std::string("New Clothes")); disabled_items.push_back(std::string("New Body Parts")); disabled_items.push_back(std::string("upload_def")); @@ -4038,6 +4066,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items disabled_items.push_back(std::string("New Script")); disabled_items.push_back(std::string("New Note")); disabled_items.push_back(std::string("New Gesture")); + disabled_items.push_back(std::string("New Material")); disabled_items.push_back(std::string("New Clothes")); disabled_items.push_back(std::string("New Body Parts")); disabled_items.push_back(std::string("upload_def")); @@ -4092,20 +4121,25 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items if (!isInboxFolder() // don't allow creation in inbox && outfits_id != mUUID) { + bool menu_items_added = false; // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) { items.push_back(std::string("New Folder")); + menu_items_added = true; } if (!isMarketplaceListingsFolder()) { items.push_back(std::string("New Script")); items.push_back(std::string("New Note")); items.push_back(std::string("New Gesture")); + items.push_back(std::string("New Material")); items.push_back(std::string("New Clothes")); items.push_back(std::string("New Body Parts")); items.push_back(std::string("New Settings")); items.push_back(std::string("upload_def")); + + menu_items_added = true; if (!LLEnvironment::instance().isInventoryEnabled()) { @@ -4113,6 +4147,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items } } + if (menu_items_added) + { + items.push_back(std::string("Create Separator")); + } } getClipboardEntries(false, items, disabled_items, flags); } @@ -4266,7 +4304,16 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items.push_back(std::string("Conference Chat Folder")); items.push_back(std::string("IM All Contacts In Folder")); } + + if (((flags & ITEM_IN_MULTI_SELECTION) == 0) && hasChildren()) + { + items.push_back(std::string("Ungroup folder items")); + } } + else + { + disabled_items.push_back(std::string("New folder from selected")); + } #ifndef LL_RELEASE_FOR_DOWNLOAD if (LLFolderType::lookupIsProtectedType(type) && is_agent_inventory) @@ -4378,6 +4425,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_GESTURE: case DAD_MESH: case DAD_SETTINGS: + case DAD_MATERIAL: accept = dragItemIntoFolder(inv_item, drop, tooltip_msg); break; case DAD_LINK: @@ -6007,6 +6055,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_GESTURE: case DAD_MESH: case DAD_SETTINGS: + case DAD_MATERIAL: { LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; const LLPermissions& perm = inv_item->getPermissions(); @@ -7198,6 +7247,39 @@ bool LLSettingsBridge::canUpdateRegion() const // +=================================================+ +// | LLMaterialBridge | +// +=================================================+ + +void LLMaterialBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +} + +void LLMaterialBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + LL_DEBUGS() << "LLMaterialBridge::buildContextMenu()" << LL_ENDL; + + if (isMarketplaceListingsFolder()) + { + menuentry_vec_t items; + menuentry_vec_t disabled_items; + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); + hide_context_entries(menu, items, disabled_items); + } + else + { + LLItemBridge::buildContextMenu(menu, flags); + } +} + + +// +=================================================+ // | LLLinkBridge | // +=================================================+ // For broken folder links. @@ -7584,6 +7666,24 @@ protected: LLSettingsBridgeAction(const LLUUID& id, LLInventoryModel* model) : LLInvFVBridgeAction(id, model) {} }; +class LLMaterialBridgeAction : public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + void doIt() override + { + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("material_editor", LLSD(item->getUUID()), TAKE_FOCUS_YES); + } + LLInvFVBridgeAction::doIt(); + } + ~LLMaterialBridgeAction() = default; +private: + LLMaterialBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {} +}; + LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, const LLUUID& uuid, @@ -7626,6 +7726,9 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_ case LLAssetType::AT_SETTINGS: action = new LLSettingsBridgeAction(uuid, model); break; + case LLAssetType::AT_MATERIAL: + action = new LLMaterialBridgeAction(uuid, model); + break; default: break; } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 0b0ef273e1..6c1ddd716b 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -637,6 +637,17 @@ protected: }; +class LLMaterialBridge : public LLItemBridge +{ +public: + LLMaterialBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid) : + LLItemBridge(inventory, root, uuid) {} + virtual void openItem(); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvFVBridgeAction // diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 707ff2b7b6..f7dc493109 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -1306,6 +1306,18 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } + if (isFilterObjectTypesWith(LLInventoryType::IT_MATERIAL)) + { + filtered_types += LLTrans::getString("Materials"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + not_filtered_types += LLTrans::getString("Materials"); + filtered_by_all_types = FALSE; + } + if (isFilterObjectTypesWith(LLInventoryType::IT_NOTECARD)) { filtered_types += LLTrans::getString("Notecards"); diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index d239b23e83..27edc8148e 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -1868,6 +1868,86 @@ void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id) } } +void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids) +{ + for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it) + { + LLInventoryItem* inv_item = gInventory.getItem(*it); + if (inv_item) + { + change_item_parent(*it, new_cat_uuid); + } + else + { + LLInventoryCategory* inv_cat = gInventory.getCategory(*it); + if (inv_cat && !LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())) + { + gInventory.changeCategoryParent((LLViewerInventoryCategory*)inv_cat, new_cat_uuid, false); + } + } + } + + LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory"); + if (!floater_inventory) + { + LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; + return; + } + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); + if (sidepanel_inventory) + { + if (sidepanel_inventory->getActivePanel()) + { + sidepanel_inventory->getActivePanel()->setSelection(new_cat_uuid, TAKE_FOCUS_YES); + LLFolderViewItem* fv_folder = sidepanel_inventory->getActivePanel()->getItemByID(new_cat_uuid); + if (fv_folder) + { + fv_folder->setOpen(TRUE); + } + } + } +} + +bool is_only_cats_selected(const uuid_vec_t& selected_uuids) +{ + for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it) + { + LLInventoryCategory* inv_cat = gInventory.getCategory(*it); + if (!inv_cat) + { + return false; + } + } + return true; +} + +bool is_only_items_selected(const uuid_vec_t& selected_uuids) +{ + for (uuid_vec_t::const_iterator it = selected_uuids.begin(); it != selected_uuids.end(); ++it) + { + LLViewerInventoryItem* inv_item = gInventory.getItem(*it); + if (!inv_item) + { + return false; + } + } + return true; +} + + +void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::string& folder_name) +{ + LLInventoryObject* first_item = gInventory.getObject(*selected_uuids.begin()); + if (!first_item) + { + return; + } + + inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids); + gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func); + +} + ///---------------------------------------------------------------------------- /// LLInventoryCollectFunctor implementations ///---------------------------------------------------------------------------- @@ -2522,6 +2602,81 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root { (new LLDirPickerThread(boost::bind(&LLInventoryAction::saveMultipleTextures, _1, selected_items, model), std::string()))->getFile(); } + else if ("new_folder_from_selected" == action) + { + + LLInventoryObject* first_item = gInventory.getObject(*ids.begin()); + if (!first_item) + { + return; + } + const LLUUID& parent_uuid = first_item->getParentUUID(); + for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + LLInventoryObject *item = gInventory.getObject(*it); + if (!item || item->getParentUUID() != parent_uuid) + { + LLNotificationsUtil::add("SameFolderRequired"); + return; + } + } + + LLSD args; + args["DESC"] = LLTrans::getString("New Folder"); + + LLNotificationsUtil::add("CreateSubfolder", args, LLSD(), + [ids](const LLSD& notification, const LLSD& response) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notification, response); + if (opt == 0) + { + std::string settings_name = response["message"].asString(); + + LLInventoryObject::correctInventoryName(settings_name); + if (settings_name.empty()) + { + settings_name = LLTrans::getString("New Folder"); + } + move_items_to_new_subfolder(ids, settings_name); + } + }); + } + else if ("ungroup_folder_items" == action) + { + if (selected_uuid_set.size() == 1) + { + LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin()); + if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())) + { + return; + } + const LLUUID &new_cat_uuid = inv_cat->getParentUUID(); + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cat_array, item_array); + LLInventoryModel::cat_array_t cats = *cat_array; + LLInventoryModel::item_array_t items = *item_array; + + for (LLInventoryModel::cat_array_t::const_iterator cat_iter = cats.begin(); cat_iter != cats.end(); ++cat_iter) + { + LLViewerInventoryCategory* cat = *cat_iter; + if (cat) + { + gInventory.changeCategoryParent(cat, new_cat_uuid, false); + } + } + for (LLInventoryModel::item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter) + { + LLViewerInventoryItem* item = *item_iter; + if(item) + { + gInventory.changeItemParent(item, new_cat_uuid, false); + } + } + gInventory.removeCategory(inv_cat->getUUID()); + gInventory.notifyObservers(); + } + } else { std::set<LLFolderViewItem*>::iterator set_iter; diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 8915bfa1e0..ba9f157e47 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -93,6 +93,10 @@ LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth); S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false); void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id); +void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::string& folder_name); +void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids); +bool is_only_cats_selected(const uuid_vec_t& selected_uuids); +bool is_only_items_selected(const uuid_vec_t& selected_uuids); /** Miscellaneous global functions ** ** diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp index 44e493fdf4..e9b0e8404a 100644 --- a/indra/newview/llinventoryicon.cpp +++ b/indra/newview/llinventoryicon.cpp @@ -99,6 +99,8 @@ LLIconDictionary::LLIconDictionary() addEntry(LLInventoryType::ICONNAME_SETTINGS_DAY, new IconEntry("Inv_SettingsDay")); addEntry(LLInventoryType::ICONNAME_SETTINGS, new IconEntry("Inv_Settings")); + addEntry(LLInventoryType::ICONNAME_MATERIAL, new IconEntry("Inv_Material")); + addEntry(LLInventoryType::ICONNAME_INVALID, new IconEntry("Inv_Invalid")); addEntry(LLInventoryType::ICONNAME_UNKNOWN, new IconEntry("Inv_Unknown")); @@ -177,6 +179,9 @@ const std::string& LLInventoryIcon::getIconName(LLAssetType::EType asset_type, case LLAssetType::AT_SETTINGS: idx = assignSettingsIcon(misc_flag); break; + case LLAssetType::AT_MATERIAL: + idx = LLInventoryType::ICONNAME_MATERIAL; + break; case LLAssetType::AT_UNKNOWN: idx = LLInventoryType::ICONNAME_UNKNOWN; default: diff --git a/indra/newview/llinventorylistitem.cpp b/indra/newview/llinventorylistitem.cpp index 12bb609df8..de6a850b57 100644 --- a/indra/newview/llinventorylistitem.cpp +++ b/indra/newview/llinventorylistitem.cpp @@ -298,31 +298,41 @@ LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem applyXUILayout(icon_params, this); mIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params); - if (mIconCtrl) - { - addChild(mIconCtrl); - } - else + if (!mIconCtrl) { LLIconCtrl::Params icon_params; icon_params.name = "item_icon"; mIconCtrl = LLUICtrlFactory::create<LLIconCtrl>(icon_params); } + if (mIconCtrl) + { + addChild(mIconCtrl); + } + else + { + LL_ERRS() << "Failed to create mIconCtrl" << LL_ENDL; + } + LLTextBox::Params text_params(params.item_name); applyXUILayout(text_params, this); mTitleCtrl = LLUICtrlFactory::create<LLTextBox>(text_params); - if (mTitleCtrl) + if (!mTitleCtrl) { - addChild(mTitleCtrl); - } - else - { - LLTextBox::Params text_aprams; + LLTextBox::Params text_params; text_params.name = "item_title"; mTitleCtrl = LLUICtrlFactory::create<LLTextBox>(text_params); } + + if (mTitleCtrl) + { + addChild(mTitleCtrl); + } + else + { + LL_ERRS() << "Failed to create mTitleCtrl" << LL_ENDL; + } } class WidgetVisibilityChanger diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 6b102c7500..cd24b3ea43 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -2010,7 +2010,43 @@ LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params) void LLAssetFilteredInventoryPanel::initFromParams(const Params& p) { - mAssetType = LLAssetType::lookup(p.filter_asset_type.getValue()); + // Init asset types + std::string types = p.filter_asset_types.getValue(); + + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("|"); + tokenizer tokens(types, sep); + tokenizer::iterator token_iter = tokens.begin(); + + memset(mAssetTypes, 0, LLAssetType::AT_COUNT * sizeof(bool)); + while (token_iter != tokens.end()) + { + const std::string& token_str = *token_iter; + LLAssetType::EType asset_type = LLAssetType::lookup(token_str); + if (asset_type > LLAssetType::AT_NONE && asset_type < LLAssetType::AT_COUNT) + { + mAssetTypes[asset_type] = true; + } + ++token_iter; + } + + // Init drag types + memset(mDragTypes, 0, EDragAndDropType::DAD_COUNT * sizeof(bool)); + for (S32 i = 0; i < LLAssetType::AT_COUNT; i++) + { + if (mAssetTypes[i]) + { + EDragAndDropType drag_type = LLViewerAssetType::lookupDragAndDropType((LLAssetType::EType)i); + if (drag_type != DAD_NONE) + { + mDragTypes[drag_type] = true; + } + } + } + // Always show AT_CATEGORY, but it shouldn't get into mDragTypes + mAssetTypes[LLAssetType::AT_CATEGORY] = true; + + // Init the panel LLInventoryPanel::initFromParams(p); U64 filter_cats = getFilter().getFilterCategoryTypes(); filter_cats &= ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS); @@ -2028,10 +2064,9 @@ BOOL LLAssetFilteredInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, B if (mAcceptsDragAndDrop) { - EDragAndDropType allow_type = LLViewerAssetType::lookupDragAndDropType(mAssetType); // Don't allow DAD_CATEGORY here since it can contain other items besides required assets // We should see everything we drop! - if (allow_type == cargo_type) + if (mDragTypes[cargo_type]) { result = LLInventoryPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); } @@ -2047,8 +2082,14 @@ bool LLAssetFilteredInventoryPanel::typedViewsFilter(const LLUUID& id, LLInvento { return false; } + LLAssetType::EType asset_type = objectp->getType(); - if (objectp->getType() != mAssetType && objectp->getType() != LLAssetType::AT_CATEGORY) + if (asset_type < 0 || asset_type >= LLAssetType::AT_COUNT) + { + return false; + } + + if (!mAssetTypes[asset_type]) { return false; } @@ -2064,11 +2105,16 @@ void LLAssetFilteredInventoryPanel::itemChanged(const LLUUID& id, U32 mask, cons return; } - if (model_item - && model_item->getType() != mAssetType - && model_item->getType() != LLAssetType::AT_CATEGORY) + if (model_item) { - return; + LLAssetType::EType asset_type = model_item->getType(); + + if (asset_type < 0 + || asset_type >= LLAssetType::AT_COUNT + || !mAssetTypes[asset_type]) + { + return; + } } LLInventoryPanel::itemChanged(id, mask, model_item); diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 552c61b915..d5219a22e7 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -393,9 +393,9 @@ public: struct Params : public LLInitParam::Block<Params, LLInventoryPanel::Params> { - Mandatory<std::string> filter_asset_type; + Mandatory<std::string> filter_asset_types; - Params() : filter_asset_type("filter_asset_type") {} + Params() : filter_asset_types("filter_asset_types") {} }; void initFromParams(const Params& p); @@ -416,7 +416,8 @@ protected: /*virtual*/ void itemChanged(const LLUUID& item_id, U32 mask, const LLInventoryObject* model_item) override; private: - LLAssetType::EType mAssetType; + bool mAssetTypes[LLAssetType::AT_COUNT]; + bool mDragTypes[EDragAndDropType::DAD_COUNT]; }; #endif // LL_LLINVENTORYPANEL_H diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 5a17332fde..c3e3fd5c1b 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -62,6 +62,7 @@ #include "pipeline.h" #include "llmaterialmgr.h" #include "llimagedimensionsinfo.h" +#include "llinventoryicon.h" #include "llviewercontrol.h" #include "lltrans.h" #include "llviewerdisplay.h" @@ -931,32 +932,7 @@ bool LLLocalBitmapMgr::addUnit() std::string filename = picker.getFirstFile(); while(!filename.empty()) { - if(!checkTextureDimensions(filename)) - { - filename = picker.getNextFile(); - continue; - } - - LLLocalBitmap* unit = new LLLocalBitmap(filename); - - if (unit->getValid()) - { - mBitmapList.push_back(unit); - add_successful = true; - } - else - { - LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n" - << "Filename: " << filename << LL_ENDL; - - LLSD notif_args; - notif_args["FNAME"] = filename; - LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args); - - delete unit; - unit = NULL; - } - + add_successful |= addUnit(filename); filename = picker.getNextFile(); } @@ -965,6 +941,49 @@ bool LLLocalBitmapMgr::addUnit() return add_successful; } +bool LLLocalBitmapMgr::addUnit(const std::vector<std::string>& filenames) +{ + bool add_successful = false; + std::vector<std::string>::const_iterator iter = filenames.begin(); + while (iter != filenames.end()) + { + if (!iter->empty()) + { + add_successful |= addUnit(*iter); + } + iter++; + } + return add_successful; +} + +bool LLLocalBitmapMgr::addUnit(const std::string& filename) +{ + if (!checkTextureDimensions(filename)) + { + return false; + } + + LLLocalBitmap* unit = new LLLocalBitmap(filename); + + if (unit->getValid()) + { + mBitmapList.push_back(unit); + return true; + } + else + { + LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n" + << "Filename: " << filename << LL_ENDL; + + LLSD notif_args; + notif_args["FNAME"] = filename; + LLNotificationsUtil::add("LocalBitmapsVerifyFail", notif_args); + + delete unit; + unit = NULL; + return false; + } +} bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename) { @@ -1071,7 +1090,9 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) { if (ctrl) { - ctrl->clearRows(); + std::string icon_name = LLInventoryIcon::getIconName( + LLAssetType::AT_TEXTURE, + LLInventoryType::IT_NONE); if (!mBitmapList.empty()) { @@ -1079,13 +1100,19 @@ void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl) iter != mBitmapList.end(); iter++) { LLSD element; - element["columns"][0]["column"] = "unit_name"; - element["columns"][0]["type"] = "text"; - element["columns"][0]["value"] = (*iter)->getShortName(); - element["columns"][1]["column"] = "unit_id_HIDDEN"; - element["columns"][1]["type"] = "text"; - element["columns"][1]["value"] = (*iter)->getTrackingID(); + element["columns"][0]["column"] = "icon"; + element["columns"][0]["type"] = "icon"; + element["columns"][0]["value"] = icon_name; + + element["columns"][1]["column"] = "unit_name"; + element["columns"][1]["type"] = "text"; + element["columns"][1]["value"] = (*iter)->getShortName(); + + LLSD data; + data["id"] = (*iter)->getTrackingID(); + data["type"] = (S32)LLAssetType::AT_TEXTURE; + element["value"] = data; ctrl->addElement(element); } diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index d5ee7efdc6..362d47142d 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -116,13 +116,15 @@ class LLLocalBitmapMgr : public LLSingleton<LLLocalBitmapMgr> ~LLLocalBitmapMgr(); public: bool addUnit(); + bool addUnit(const std::vector<std::string>& filenames); + bool addUnit(const std::string& filename); void delUnit(LLUUID tracking_id); bool checkTextureDimensions(std::string filename); LLUUID getWorldID(LLUUID tracking_id); bool isLocal(LLUUID world_id); std::string getFilename(LLUUID tracking_id); - + void feedScrollList(LLScrollListCtrl* ctrl); void doUpdates(); void setNeedsRebake(); diff --git a/indra/newview/lllocalgltfmaterials.cpp b/indra/newview/lllocalgltfmaterials.cpp new file mode 100644 index 0000000000..ef488e9ef4 --- /dev/null +++ b/indra/newview/lllocalgltfmaterials.cpp @@ -0,0 +1,546 @@ +/** + * @file lllocalrendermaterials.cpp + * @brief Local GLTF materials source + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +/* precompiled headers */ +#include "llviewerprecompiledheaders.h" + +/* own header */ +#include "lllocalgltfmaterials.h" + +/* boost: will not compile unless equivalent is undef'd, beware. */ +#include "fix_macros.h" +#include <boost/filesystem.hpp> + +/* time headers */ +#include <time.h> +#include <ctime> + +/* misc headers */ +#include "llfilepicker.h" +#include "llgltfmateriallist.h" +#include "llimage.h" +#include "llinventoryicon.h" +#include "llmaterialmgr.h" +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "lltinygltfhelper.h" +#include "llviewertexture.h" +#include "tinygltf/tiny_gltf.h" + +/*=======================================*/ +/* Formal declarations, constants, etc. */ +/*=======================================*/ + +static const F32 LL_LOCAL_TIMER_HEARTBEAT = 3.0; +static const S32 LL_LOCAL_UPDATE_RETRIES = 5; + +/*=======================================*/ +/* LLLocalGLTFMaterial: unit class */ +/*=======================================*/ +LLLocalGLTFMaterial::LLLocalGLTFMaterial(std::string filename) + : mFilename(filename) + , mShortName(gDirUtilp->getBaseFileName(filename, true)) + , mValid(false) + , mLastModified() + , mLinkStatus(LS_ON) + , mUpdateRetries(LL_LOCAL_UPDATE_RETRIES) +{ + mTrackingID.generate(); + + /* extension */ + std::string temp_exten = gDirUtilp->getExtension(mFilename); + + if (temp_exten == "gltf") + { + mExtension = ET_MATERIAL_GLTF; + } + else if (temp_exten == "glb") + { + mExtension = ET_MATERIAL_GLB; + } + else + { + LL_WARNS() << "File of no valid extension given, local material creation aborted." << "\n" + << "Filename: " << mFilename << LL_ENDL; + return; // no valid extension. + } + + /* next phase of unit creation is nearly the same as an update cycle. + we're running updateSelf as a special case with the optional UT_FIRSTUSE + which omits the parts associated with removing the outdated texture */ + mValid = updateSelf(); +} + +LLLocalGLTFMaterial::~LLLocalGLTFMaterial() +{ + // delete self from material list + gGLTFMaterialList.removeMaterial(mWorldID); +} + +/* accessors */ +std::string LLLocalGLTFMaterial::getFilename() +{ + return mFilename; +} + +std::string LLLocalGLTFMaterial::getShortName() +{ + return mShortName; +} + +LLUUID LLLocalGLTFMaterial::getTrackingID() +{ + return mTrackingID; +} + +LLUUID LLLocalGLTFMaterial::getWorldID() +{ + return mWorldID; +} + +bool LLLocalGLTFMaterial::getValid() +{ + return mValid; +} + +/* update functions */ +bool LLLocalGLTFMaterial::updateSelf() +{ + bool updated = false; + + if (mLinkStatus == LS_ON) + { + // verifying that the file exists + if (gDirUtilp->fileExists(mFilename)) + { + // verifying that the file has indeed been modified + +#ifndef LL_WINDOWS + const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(mFilename)); +#else + const std::time_t temp_time = boost::filesystem::last_write_time(boost::filesystem::path(utf8str_to_utf16str(mFilename))); +#endif + LLSD new_last_modified = asctime(localtime(&temp_time)); + + if (mLastModified.asString() != new_last_modified.asString()) + { + LLPointer<LLGLTFMaterial> raw_material = new LLGLTFMaterial(); + if (loadMaterial(raw_material)) + { + // decode is successful, we can safely proceed. + if (mWorldID.isNull()) + { + mWorldID.generate(); + } + mLastModified = new_last_modified; + + // will replace material if it already exists + gGLTFMaterialList.addMaterial(mWorldID, raw_material); + + mUpdateRetries = LL_LOCAL_UPDATE_RETRIES; + updated = true; + } + + // if decoding failed, we get here and it will attempt to decode it in the next cycles + // until mUpdateRetries runs out. this is done because some software lock the material while writing to it + else + { + if (mUpdateRetries) + { + mUpdateRetries--; + } + else + { + LL_WARNS() << "During the update process the following file was found" << "\n" + << "but could not be opened or decoded for " << LL_LOCAL_UPDATE_RETRIES << " attempts." << "\n" + << "Filename: " << mFilename << "\n" + << "Disabling further update attempts for this file." << LL_ENDL; + + LLSD notif_args; + notif_args["FNAME"] = mFilename; + notif_args["NRETRIES"] = LL_LOCAL_UPDATE_RETRIES; + LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args); + + mLinkStatus = LS_BROKEN; + } + } + } + + } // end if file exists + + else + { + LL_WARNS() << "During the update process, the following file was not found." << "\n" + << "Filename: " << mFilename << "\n" + << "Disabling further update attempts for this file." << LL_ENDL; + + LLSD notif_args; + notif_args["FNAME"] = mFilename; + LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args); + + mLinkStatus = LS_BROKEN; + } + } + + return updated; +} + +bool LLLocalGLTFMaterial::loadMaterial(LLPointer<LLGLTFMaterial> mat) +{ + bool decode_successful = false; + + switch (mExtension) + { + case ET_MATERIAL_GLTF: + case ET_MATERIAL_GLB: + { + tinygltf::TinyGLTF loader; + std::string error_msg; + std::string warn_msg; + + tinygltf::Model model_in; + + std::string filename_lc = mFilename; + LLStringUtil::toLower(filename_lc); + + // Load a tinygltf model fom a file. Assumes that the input filename has already been + // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish. + if (std::string::npos == filename_lc.rfind(".gltf")) + { // file is binary + decode_successful = loader.LoadBinaryFromFile(&model_in, &error_msg, &warn_msg, filename_lc); + } + else + { // file is ascii + decode_successful = loader.LoadASCIIFromFile(&model_in, &error_msg, &warn_msg, filename_lc); + } + + if (!decode_successful) + { + LL_WARNS() << "Cannot Upload Material, error: " << error_msg + << ", warning:" << warn_msg + << " file: " << mFilename + << LL_ENDL; + break; + } + + if (model_in.materials.empty()) + { + // materials are missing + LL_WARNS() << "Cannot Upload Material, Material missing, " << mFilename << LL_ENDL; + decode_successful = false; + break; + } + + // sets everything, but textures will have inaccurate ids + LLTinyGLTFHelper::setFromModel(mat, model_in); + + std::string folder = gDirUtilp->getDirName(filename_lc); + tinygltf::Material material_in = model_in.materials[0]; + + // get albedo texture + LLPointer<LLImageRaw> albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index); + // get normal map + LLPointer<LLImageRaw> normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index); + // get metallic-roughness texture + LLPointer<LLImageRaw> mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index); + // get emissive texture + LLPointer<LLImageRaw> emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index); + // get occlusion map if needed + LLPointer<LLImageRaw> occlusion_img; + if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index) + { + occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index); + } + + // todo: pass it into local bitmaps? + LLTinyGLTFHelper::initFetchedTextures(material_in, + albedo_img, normal_img, mr_img, emissive_img, occlusion_img, + mAlbedoFetched, mNormalFetched, mMRFetched, mEmissiveFetched); + + if (mAlbedoFetched) + { + mat->mAlbedoId = mAlbedoFetched->getID(); + } + if (mNormalFetched) + { + mat->mNormalId = mNormalFetched->getID(); + } + if (mMRFetched) + { + mat->mMetallicRoughnessId = mMRFetched->getID(); + } + if (mEmissiveFetched) + { + mat->mEmissiveId = mEmissiveFetched->getID(); + } + + break; + } + + default: + { + // separating this into -several- LL_WARNS() calls because in the extremely unlikely case that this happens + // accessing mFilename and any other object properties might very well crash the viewer. + // getting here should be impossible, or there's been a pretty serious bug. + + LL_WARNS() << "During a decode attempt, the following local material had no properly assigned extension." << LL_ENDL; + LL_WARNS() << "Filename: " << mFilename << LL_ENDL; + LL_WARNS() << "Disabling further update attempts for this file." << LL_ENDL; + mLinkStatus = LS_BROKEN; + } + } + + return decode_successful; +} + + +/*=======================================*/ +/* LLLocalGLTFMaterialTimer: timer class */ +/*=======================================*/ +LLLocalGLTFMaterialTimer::LLLocalGLTFMaterialTimer() : LLEventTimer(LL_LOCAL_TIMER_HEARTBEAT) +{ +} + +LLLocalGLTFMaterialTimer::~LLLocalGLTFMaterialTimer() +{ +} + +void LLLocalGLTFMaterialTimer::startTimer() +{ + mEventTimer.start(); +} + +void LLLocalGLTFMaterialTimer::stopTimer() +{ + mEventTimer.stop(); +} + +bool LLLocalGLTFMaterialTimer::isRunning() +{ + return mEventTimer.getStarted(); +} + +BOOL LLLocalGLTFMaterialTimer::tick() +{ + // todo: do on idle? No point in timer + LLLocalGLTFMaterialMgr::getInstance()->doUpdates(); + return FALSE; +} + +/*=======================================*/ +/* LLLocalGLTFMaterialMgr: manager class */ +/*=======================================*/ +LLLocalGLTFMaterialMgr::LLLocalGLTFMaterialMgr() +{ +} + +LLLocalGLTFMaterialMgr::~LLLocalGLTFMaterialMgr() +{ + std::for_each(mMaterialList.begin(), mMaterialList.end(), DeletePointer()); + mMaterialList.clear(); +} + +bool LLLocalGLTFMaterialMgr::addUnit() +{ + bool add_successful = false; + + LLFilePicker& picker = LLFilePicker::instance(); + if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_MATERIAL)) + { + mTimer.stopTimer(); + + std::string filename = picker.getFirstFile(); + while (!filename.empty()) + { + add_successful |= addUnit(filename); + filename = picker.getNextFile(); + } + + mTimer.startTimer(); + } + + return add_successful; +} + +bool LLLocalGLTFMaterialMgr::addUnit(const std::vector<std::string>& filenames) +{ + bool add_successful = false; + std::vector<std::string>::const_iterator iter = filenames.begin(); + while (iter != filenames.end()) + { + if (!iter->empty()) + { + add_successful |= addUnit(*iter); + } + iter++; + } + return add_successful; +} + +bool LLLocalGLTFMaterialMgr::addUnit(const std::string& filename) +{ + LLLocalGLTFMaterial* unit = new LLLocalGLTFMaterial(filename); + + if (unit->getValid()) + { + mMaterialList.push_back(unit); + return true; + } + else + { + LL_WARNS() << "Attempted to add invalid or unreadable image file, attempt cancelled.\n" + << "Filename: " << filename << LL_ENDL; + + LLSD notif_args; + notif_args["FNAME"] = filename; + LLNotificationsUtil::add("LocalGLTFVerifyFail", notif_args); + + delete unit; + unit = NULL; + + return false; + } +} + +void LLLocalGLTFMaterialMgr::delUnit(LLUUID tracking_id) +{ + if (!mMaterialList.empty()) + { + std::vector<LLLocalGLTFMaterial*> to_delete; + for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) + { /* finding which ones we want deleted and making a separate list */ + LLLocalGLTFMaterial* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + to_delete.push_back(unit); + } + } + + for (std::vector<LLLocalGLTFMaterial*>::iterator del_iter = to_delete.begin(); + del_iter != to_delete.end(); del_iter++) + { /* iterating over a temporary list, hence preserving the iterator validity while deleting. */ + LLLocalGLTFMaterial* unit = *del_iter; + mMaterialList.remove(unit); + delete unit; + unit = NULL; + } + } +} + +LLUUID LLLocalGLTFMaterialMgr::getWorldID(LLUUID tracking_id) +{ + LLUUID world_id = LLUUID::null; + + for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) + { + LLLocalGLTFMaterial* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + world_id = unit->getWorldID(); + } + } + + return world_id; +} + +bool LLLocalGLTFMaterialMgr::isLocal(const LLUUID world_id) +{ + for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) + { + LLLocalGLTFMaterial* unit = *iter; + if (unit->getWorldID() == world_id) + { + return true; + } + } + return false; +} + +std::string LLLocalGLTFMaterialMgr::getFilename(LLUUID tracking_id) +{ + std::string filename = ""; + + for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) + { + LLLocalGLTFMaterial* unit = *iter; + if (unit->getTrackingID() == tracking_id) + { + filename = unit->getFilename(); + } + } + + return filename; +} + +// probably shouldn't be here, but at the moment this mirrors lllocalbitmaps +void LLLocalGLTFMaterialMgr::feedScrollList(LLScrollListCtrl* ctrl) +{ + if (ctrl) + { + if (!mMaterialList.empty()) + { + std::string icon_name = LLInventoryIcon::getIconName( + LLAssetType::AT_MATERIAL, + LLInventoryType::IT_NONE); + + for (local_list_iter iter = mMaterialList.begin(); + iter != mMaterialList.end(); iter++) + { + LLSD element; + + element["columns"][0]["column"] = "icon"; + element["columns"][0]["type"] = "icon"; + element["columns"][0]["value"] = icon_name; + + element["columns"][1]["column"] = "unit_name"; + element["columns"][1]["type"] = "text"; + element["columns"][1]["value"] = (*iter)->getShortName(); + + LLSD data; + data["id"] = (*iter)->getTrackingID(); + data["type"] = (S32)LLAssetType::AT_MATERIAL; + element["value"] = data; + + ctrl->addElement(element); + } + } + } + +} + +void LLLocalGLTFMaterialMgr::doUpdates() +{ + // preventing theoretical overlap in cases with huge number of loaded images. + mTimer.stopTimer(); + + for (local_list_iter iter = mMaterialList.begin(); iter != mMaterialList.end(); iter++) + { + (*iter)->updateSelf(); + } + + mTimer.startTimer(); +} + diff --git a/indra/newview/lllocalgltfmaterials.h b/indra/newview/lllocalgltfmaterials.h new file mode 100644 index 0000000000..7f5b06e10a --- /dev/null +++ b/indra/newview/lllocalgltfmaterials.h @@ -0,0 +1,125 @@ +/** + * @file lllocalrendermaterials.h + * @brief Local GLTF materials header + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LOCALGLTFMATERIALS_H +#define LL_LOCALGLTFMATERIALS_H + +#include "lleventtimer.h" +#include "llpointer.h" + +class LLScrollListCtrl; +class LLGLTFMaterial; +class LLViewerObject; +class LLViewerFetchedTexture; + +class LLLocalGLTFMaterial +{ +public: /* main */ + LLLocalGLTFMaterial(std::string filename); + ~LLLocalGLTFMaterial(); + +public: /* accessors */ + std::string getFilename(); + std::string getShortName(); + LLUUID getTrackingID(); + LLUUID getWorldID(); + bool getValid(); + +public: + bool updateSelf(); + +private: + bool loadMaterial(LLPointer<LLGLTFMaterial> raw); + +private: /* private enums */ + enum ELinkStatus + { + LS_ON, + LS_BROKEN, + }; + + enum EExtension + { + ET_MATERIAL_GLTF, + ET_MATERIAL_GLB, + }; + +private: /* members */ + std::string mFilename; + std::string mShortName; + LLUUID mTrackingID; + LLUUID mWorldID; + bool mValid; + LLSD mLastModified; + EExtension mExtension; + ELinkStatus mLinkStatus; + S32 mUpdateRetries; + + // material needs to maintain textures + LLPointer<LLViewerFetchedTexture> mAlbedoFetched; + LLPointer<LLViewerFetchedTexture> mNormalFetched; + LLPointer<LLViewerFetchedTexture> mMRFetched; + LLPointer<LLViewerFetchedTexture> mEmissiveFetched; +}; + +class LLLocalGLTFMaterialTimer : public LLEventTimer +{ +public: + LLLocalGLTFMaterialTimer(); + ~LLLocalGLTFMaterialTimer(); + +public: + void startTimer(); + void stopTimer(); + bool isRunning(); + BOOL tick(); +}; + +class LLLocalGLTFMaterialMgr : public LLSingleton<LLLocalGLTFMaterialMgr> +{ + LLSINGLETON(LLLocalGLTFMaterialMgr); + ~LLLocalGLTFMaterialMgr(); +public: + bool addUnit(); + bool addUnit(const std::vector<std::string>& filenames); + bool addUnit(const std::string& filename); + void delUnit(LLUUID tracking_id); + + LLUUID getWorldID(LLUUID tracking_id); + bool isLocal(LLUUID world_id); + std::string getFilename(LLUUID tracking_id); + + void feedScrollList(LLScrollListCtrl* ctrl); + void doUpdates(); + +private: + std::list<LLLocalGLTFMaterial*> mMaterialList; + LLLocalGLTFMaterialTimer mTimer; + typedef std::list<LLLocalGLTFMaterial*>::iterator local_list_iter; +}; + +#endif // LL_LOCALGLTFMATERIALS_H + diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index a3d0eb5796..82ecfbd4dc 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -280,7 +280,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia mRequestData["options"] = requested_options; mRequestData["http_params"] = http_params; #if LL_RELEASE_FOR_DOWNLOAD - mRequestData["wait_for_updater"] = !gSavedSettings.getBOOL("CmdLineSkipUpdater") && !LLAppViewer::instance()->isUpdaterMissing(); + mRequestData["wait_for_updater"] = LLAppViewer::instance()->waitForUpdater(); #else mRequestData["wait_for_updater"] = false; #endif diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp new file mode 100644 index 0000000000..2052f252b3 --- /dev/null +++ b/indra/newview/llmaterialeditor.cpp @@ -0,0 +1,1907 @@ +/** + * @file llmaterialeditor.cpp + * @brief Implementation of the notecard editor + * + * $LicenseInfo:firstyear=2022&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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llmaterialeditor.h" + +#include "llagent.h" +#include "llagentbenefits.h" +#include "llappviewer.h" +#include "llcombobox.h" +#include "llinventorymodel.h" +#include "llnotificationsutil.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewermenufile.h" +#include "llviewertexture.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llstatusbar.h" // can_afford_transaction() +#include "llviewerinventory.h" +#include "llinventory.h" +#include "llviewerregion.h" +#include "llvovolume.h" +#include "roles_constants.h" +#include "llviewerobjectlist.h" +#include "llfloaterreg.h" +#include "llfilesystem.h" +#include "llsdserialize.h" +#include "llimagej2c.h" +#include "llviewertexturelist.h" +#include "llfloaterperms.h" + +#include "tinygltf/tiny_gltf.h" +#include "lltinygltfhelper.h" +#include <strstream> + + +const std::string MATERIAL_ALBEDO_DEFAULT_NAME = "Albedo"; +const std::string MATERIAL_NORMAL_DEFAULT_NAME = "Normal"; +const std::string MATERIAL_METALLIC_DEFAULT_NAME = "Metallic Roughness"; +const std::string MATERIAL_EMISSIVE_DEFAULT_NAME = "Emissive"; + + +class LLMaterialEditorCopiedCallback : public LLInventoryCallback +{ +public: + LLMaterialEditorCopiedCallback(const std::string &buffer, const LLUUID &old_item_id) : mBuffer(buffer), mOldItemId(old_item_id) {} + + virtual void fire(const LLUUID& inv_item_id) + { + LLMaterialEditor::finishSaveAs(mOldItemId, inv_item_id, mBuffer); + } + +private: + std::string mBuffer; + LLUUID mOldItemId; +}; + +///---------------------------------------------------------------------------- +/// Class LLMaterialEditor +///---------------------------------------------------------------------------- + +// Default constructor +LLMaterialEditor::LLMaterialEditor(const LLSD& key) + : LLPreview(key) + , mHasUnsavedChanges(false) + , mExpectedUploadCost(0) + , mUploadingTexturesCount(0) +{ + const LLInventoryItem* item = getItem(); + if (item) + { + mAssetID = item->getAssetUUID(); + } +} + +BOOL LLMaterialEditor::postBuild() +{ + mAlbedoTextureCtrl = getChild<LLTextureCtrl>("albedo_texture"); + mMetallicTextureCtrl = getChild<LLTextureCtrl>("metallic_roughness_texture"); + mEmissiveTextureCtrl = getChild<LLTextureCtrl>("emissive_texture"); + mNormalTextureCtrl = getChild<LLTextureCtrl>("normal_texture"); + + mAlbedoTextureCtrl->setCommitCallback(boost::bind(&LLMaterialEditor::onCommitAlbedoTexture, this, _1, _2)); + mMetallicTextureCtrl->setCommitCallback(boost::bind(&LLMaterialEditor::onCommitMetallicTexture, this, _1, _2)); + mEmissiveTextureCtrl->setCommitCallback(boost::bind(&LLMaterialEditor::onCommitEmissiveTexture, this, _1, _2)); + mNormalTextureCtrl->setCommitCallback(boost::bind(&LLMaterialEditor::onCommitNormalTexture, this, _1, _2)); + + childSetAction("save", boost::bind(&LLMaterialEditor::onClickSave, this)); + childSetAction("save_as", boost::bind(&LLMaterialEditor::onClickSaveAs, this)); + childSetAction("cancel", boost::bind(&LLMaterialEditor::onClickCancel, this)); + + S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); + getChild<LLUICtrl>("albedo_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + getChild<LLUICtrl>("metallic_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + getChild<LLUICtrl>("emissive_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + getChild<LLUICtrl>("normal_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost)); + + boost::function<void(LLUICtrl*, void*)> changes_callback = [this](LLUICtrl * ctrl, void*) + { + setHasUnsavedChanges(true); + // Apply changes to object live + applyToSelection(); + }; + + childSetCommitCallback("double sided", changes_callback, NULL); + + // Albedo + childSetCommitCallback("albedo color", changes_callback, NULL); + childSetCommitCallback("transparency", changes_callback, NULL); + childSetCommitCallback("alpha mode", changes_callback, NULL); + childSetCommitCallback("alpha cutoff", changes_callback, NULL); + + // Metallic-Roughness + childSetCommitCallback("metalness factor", changes_callback, NULL); + childSetCommitCallback("roughness factor", changes_callback, NULL); + + // Metallic-Roughness + childSetCommitCallback("metalness factor", changes_callback, NULL); + childSetCommitCallback("roughness factor", changes_callback, NULL); + + // Emissive + childSetCommitCallback("emissive color", changes_callback, NULL); + + childSetVisible("unsaved_changes", mHasUnsavedChanges); + + // Todo: + // Disable/enable setCanApplyImmediately() based on + // working from inventory, upload or editing inworld + + return LLPreview::postBuild(); +} + +void LLMaterialEditor::onClickCloseBtn(bool app_quitting) +{ + if (app_quitting) + { + closeFloater(app_quitting); + } + else + { + onClickCancel(); + } +} + +void LLMaterialEditor::onClose(bool app_quitting) +{ + // todo: will only revert whatever was recently selected, + // Later should work based of tools floater + LLSelectMgr::getInstance()->selectionRevertGLTFMaterials(); + + LLPreview::onClose(app_quitting); +} + +LLUUID LLMaterialEditor::getAlbedoId() +{ + return mAlbedoTextureCtrl->getValue().asUUID(); +} + +void LLMaterialEditor::setAlbedoId(const LLUUID& id) +{ + mAlbedoTextureCtrl->setValue(id); + mAlbedoTextureCtrl->setDefaultImageAssetID(id); +} + +void LLMaterialEditor::setAlbedoUploadId(const LLUUID& id) +{ + // Might be better to use local textures and + // assign a fee in case of a local texture + if (id.notNull()) + { + // todo: this does not account for posibility of texture + // being from inventory, need to check that + childSetValue("albedo_upload_fee", getString("upload_fee_string")); + // Only set if we will need to upload this texture + mAlbedoTextureUploadId = id; + } + setHasUnsavedChanges(true); +} + +LLColor4 LLMaterialEditor::getAlbedoColor() +{ + LLColor4 ret = LLColor4(childGetValue("albedo color")); + ret.mV[3] = getTransparency(); + return ret; +} + +void LLMaterialEditor::setAlbedoColor(const LLColor4& color) +{ + childSetValue("albedo color", color.getValue()); + setTransparency(color.mV[3]); +} + +F32 LLMaterialEditor::getTransparency() +{ + return childGetValue("transparency").asReal(); +} + +void LLMaterialEditor::setTransparency(F32 transparency) +{ + childSetValue("transparency", transparency); +} + +std::string LLMaterialEditor::getAlphaMode() +{ + return childGetValue("alpha mode").asString(); +} + +void LLMaterialEditor::setAlphaMode(const std::string& alpha_mode) +{ + childSetValue("alpha mode", alpha_mode); +} + +F32 LLMaterialEditor::getAlphaCutoff() +{ + return childGetValue("alpha cutoff").asReal(); +} + +void LLMaterialEditor::setAlphaCutoff(F32 alpha_cutoff) +{ + childSetValue("alpha cutoff", alpha_cutoff); +} + +void LLMaterialEditor::setMaterialName(const std::string &name) +{ + setTitle(name); + mMaterialName = name; +} + +LLUUID LLMaterialEditor::getMetallicRoughnessId() +{ + return mMetallicTextureCtrl->getValue().asUUID(); +} + +void LLMaterialEditor::setMetallicRoughnessId(const LLUUID& id) +{ + mMetallicTextureCtrl->setValue(id); + mMetallicTextureCtrl->setDefaultImageAssetID(id); +} + +void LLMaterialEditor::setMetallicRoughnessUploadId(const LLUUID& id) +{ + if (id.notNull()) + { + // todo: this does not account for posibility of texture + // being from inventory, need to check that + childSetValue("metallic_upload_fee", getString("upload_fee_string")); + mMetallicTextureUploadId = id; + } + setHasUnsavedChanges(true); +} + +F32 LLMaterialEditor::getMetalnessFactor() +{ + return childGetValue("metalness factor").asReal(); +} + +void LLMaterialEditor::setMetalnessFactor(F32 factor) +{ + childSetValue("metalness factor", factor); +} + +F32 LLMaterialEditor::getRoughnessFactor() +{ + return childGetValue("roughness factor").asReal(); +} + +void LLMaterialEditor::setRoughnessFactor(F32 factor) +{ + childSetValue("roughness factor", factor); +} + +LLUUID LLMaterialEditor::getEmissiveId() +{ + return mEmissiveTextureCtrl->getValue().asUUID(); +} + +void LLMaterialEditor::setEmissiveId(const LLUUID& id) +{ + mEmissiveTextureCtrl->setValue(id); + mEmissiveTextureCtrl->setDefaultImageAssetID(id); +} + +void LLMaterialEditor::setEmissiveUploadId(const LLUUID& id) +{ + if (id.notNull()) + { + // todo: this does not account for posibility of texture + // being from inventory, need to check that + childSetValue("emissive_upload_fee", getString("upload_fee_string")); + mEmissiveTextureUploadId = id; + } + setHasUnsavedChanges(true); +} + +LLColor4 LLMaterialEditor::getEmissiveColor() +{ + return LLColor4(childGetValue("emissive color")); +} + +void LLMaterialEditor::setEmissiveColor(const LLColor4& color) +{ + childSetValue("emissive color", color.getValue()); +} + +LLUUID LLMaterialEditor::getNormalId() +{ + return mNormalTextureCtrl->getValue().asUUID(); +} + +void LLMaterialEditor::setNormalId(const LLUUID& id) +{ + mNormalTextureCtrl->setValue(id); + mNormalTextureCtrl->setDefaultImageAssetID(id); +} + +void LLMaterialEditor::setNormalUploadId(const LLUUID& id) +{ + if (id.notNull()) + { + // todo: this does not account for posibility of texture + // being from inventory, need to check that + childSetValue("normal_upload_fee", getString("upload_fee_string")); + mNormalTextureUploadId = id; + } + setHasUnsavedChanges(true); +} + +bool LLMaterialEditor::getDoubleSided() +{ + return childGetValue("double sided").asBoolean(); +} + +void LLMaterialEditor::setDoubleSided(bool double_sided) +{ + childSetValue("double sided", double_sided); +} + +void LLMaterialEditor::setHasUnsavedChanges(bool value) +{ + if (value != mHasUnsavedChanges) + { + mHasUnsavedChanges = value; + childSetVisible("unsaved_changes", value); + } + + S32 upload_texture_count = 0; + if (mAlbedoTextureUploadId.notNull() && mAlbedoTextureUploadId == getAlbedoId()) + { + upload_texture_count++; + } + if (mMetallicTextureUploadId.notNull() && mMetallicTextureUploadId == getMetallicRoughnessId()) + { + upload_texture_count++; + } + if (mEmissiveTextureUploadId.notNull() && mEmissiveTextureUploadId == getEmissiveId()) + { + upload_texture_count++; + } + if (mNormalTextureUploadId.notNull() && mNormalTextureUploadId == getNormalId()) + { + upload_texture_count++; + } + + mExpectedUploadCost = upload_texture_count * LLAgentBenefitsMgr::current().getTextureUploadCost(); + getChild<LLUICtrl>("total_upload_fee")->setTextArg("[FEE]", llformat("%d", mExpectedUploadCost)); +} + +void LLMaterialEditor::setCanSaveAs(BOOL value) +{ + childSetEnabled("save_as", value); +} + +void LLMaterialEditor::setCanSave(BOOL value) +{ + childSetEnabled("save", value); +} + +void LLMaterialEditor::onCommitAlbedoTexture(LLUICtrl * ctrl, const LLSD & data) +{ + // might be better to use arrays, to have a single callback + // and not to repeat the same thing for each tecture control + LLUUID new_val = mAlbedoTextureCtrl->getValue().asUUID(); + if (new_val == mAlbedoTextureUploadId && mAlbedoTextureUploadId.notNull()) + { + childSetValue("albedo_upload_fee", getString("upload_fee_string")); + } + else + { + // Texture picker has 'apply now' with 'cancel' support. + // Keep mAlbedoJ2C and mAlbedoFetched, it's our storage in + // case user decides to cancel changes. + // Without mAlbedoFetched, viewer will eventually cleanup + // the texture that is not in use + childSetValue("albedo_upload_fee", getString("no_upload_fee_string")); + } + setHasUnsavedChanges(true); + applyToSelection(); +} + +void LLMaterialEditor::onCommitMetallicTexture(LLUICtrl * ctrl, const LLSD & data) +{ + LLUUID new_val = mMetallicTextureCtrl->getValue().asUUID(); + if (new_val == mMetallicTextureUploadId && mMetallicTextureUploadId.notNull()) + { + childSetValue("metallic_upload_fee", getString("upload_fee_string")); + } + else + { + childSetValue("metallic_upload_fee", getString("no_upload_fee_string")); + } + setHasUnsavedChanges(true); + applyToSelection(); +} + +void LLMaterialEditor::onCommitEmissiveTexture(LLUICtrl * ctrl, const LLSD & data) +{ + LLUUID new_val = mEmissiveTextureCtrl->getValue().asUUID(); + if (new_val == mEmissiveTextureUploadId && mEmissiveTextureUploadId.notNull()) + { + childSetValue("emissive_upload_fee", getString("upload_fee_string")); + } + else + { + childSetValue("emissive_upload_fee", getString("no_upload_fee_string")); + } + setHasUnsavedChanges(true); + applyToSelection(); +} + +void LLMaterialEditor::onCommitNormalTexture(LLUICtrl * ctrl, const LLSD & data) +{ + LLUUID new_val = mNormalTextureCtrl->getValue().asUUID(); + if (new_val == mNormalTextureUploadId && mNormalTextureUploadId.notNull()) + { + childSetValue("normal_upload_fee", getString("upload_fee_string")); + } + else + { + childSetValue("normal_upload_fee", getString("no_upload_fee_string")); + } + setHasUnsavedChanges(true); + applyToSelection(); +} + + +static void write_color(const LLColor4& color, std::vector<double>& c) +{ + for (int i = 0; i < c.size(); ++i) // NOTE -- use c.size because some gltf colors are 3-component + { + c[i] = color.mV[i]; + } +} + +static U32 write_texture(const LLUUID& id, tinygltf::Model& model) +{ + tinygltf::Image image; + image.uri = id.asString(); + model.images.push_back(image); + U32 image_idx = model.images.size() - 1; + + tinygltf::Texture texture; + texture.source = image_idx; + model.textures.push_back(texture); + U32 texture_idx = model.textures.size() - 1; + + return texture_idx; +} + + +void LLMaterialEditor::onClickSave() +{ + if (!can_afford_transaction(mExpectedUploadCost)) + { + LLSD args; + args["COST"] = llformat("%d", mExpectedUploadCost); + LLNotificationsUtil::add("ErrorCannotAffordUpload", args); + return; + } + + applyToSelection(); + saveIfNeeded(); +} + + +std::string LLMaterialEditor::getGLTFJson(bool prettyprint) +{ + tinygltf::Model model; + getGLTFModel(model); + + std::ostringstream str; + + tinygltf::TinyGLTF gltf; + + gltf.WriteGltfSceneToStream(&model, str, prettyprint, false); + + std::string dump = str.str(); + + return dump; +} + +void LLMaterialEditor::getGLBData(std::vector<U8>& data) +{ + tinygltf::Model model; + getGLTFModel(model); + + std::ostringstream str; + + tinygltf::TinyGLTF gltf; + + gltf.WriteGltfSceneToStream(&model, str, false, true); + + std::string dump = str.str(); + + data.resize(dump.length()); + + memcpy(&data[0], dump.c_str(), dump.length()); +} + +void LLMaterialEditor::getGLTFModel(tinygltf::Model& model) +{ + model.materials.resize(1); + tinygltf::PbrMetallicRoughness& pbrMaterial = model.materials[0].pbrMetallicRoughness; + + // write albedo + LLColor4 albedo_color = getAlbedoColor(); + albedo_color.mV[3] = getTransparency(); + write_color(albedo_color, pbrMaterial.baseColorFactor); + + model.materials[0].alphaCutoff = getAlphaCutoff(); + model.materials[0].alphaMode = getAlphaMode(); + + LLUUID albedo_id = getAlbedoId(); + + if (albedo_id.notNull()) + { + U32 texture_idx = write_texture(albedo_id, model); + + pbrMaterial.baseColorTexture.index = texture_idx; + } + + // write metallic/roughness + F32 metalness = getMetalnessFactor(); + F32 roughness = getRoughnessFactor(); + + pbrMaterial.metallicFactor = metalness; + pbrMaterial.roughnessFactor = roughness; + + LLUUID mr_id = getMetallicRoughnessId(); + if (mr_id.notNull()) + { + U32 texture_idx = write_texture(mr_id, model); + pbrMaterial.metallicRoughnessTexture.index = texture_idx; + } + + //write emissive + LLColor4 emissive_color = getEmissiveColor(); + model.materials[0].emissiveFactor.resize(3); + write_color(emissive_color, model.materials[0].emissiveFactor); + + LLUUID emissive_id = getEmissiveId(); + if (emissive_id.notNull()) + { + U32 idx = write_texture(emissive_id, model); + model.materials[0].emissiveTexture.index = idx; + } + + //write normal + LLUUID normal_id = getNormalId(); + if (normal_id.notNull()) + { + U32 idx = write_texture(normal_id, model); + model.materials[0].normalTexture.index = idx; + } + + //write doublesided + model.materials[0].doubleSided = getDoubleSided(); + + model.asset.version = "2.0"; +} + +std::string LLMaterialEditor::getEncodedAsset() +{ + LLSD asset; + asset["version"] = "1.0"; + asset["type"] = "GLTF 2.0"; + asset["data"] = getGLTFJson(false); + + std::ostringstream str; + LLSDSerialize::serialize(asset, str, LLSDSerialize::LLSD_BINARY); + + return str.str(); +} + +bool LLMaterialEditor::decodeAsset(const std::vector<char>& buffer) +{ + LLSD asset; + + std::istrstream str(&buffer[0], buffer.size()); + if (LLSDSerialize::deserialize(asset, str, buffer.size())) + { + if (asset.has("version") && asset["version"] == "1.0") + { + if (asset.has("type") && asset["type"] == "GLTF 2.0") + { + if (asset.has("data") && asset["data"].isString()) + { + std::string data = asset["data"]; + + tinygltf::TinyGLTF gltf; + tinygltf::TinyGLTF loader; + std::string error_msg; + std::string warn_msg; + + tinygltf::Model model_in; + + if (loader.LoadASCIIFromString(&model_in, &error_msg, &warn_msg, data.c_str(), data.length(), "")) + { + return setFromGltfModel(model_in, true); + } + else + { + LL_WARNS() << "Failed to decode material asset: " << LL_ENDL; + LL_WARNS() << warn_msg << LL_ENDL; + LL_WARNS() << error_msg << LL_ENDL; + } + } + } + } + } + else + { + LL_WARNS() << "Failed to deserialize material LLSD" << LL_ENDL; + } + + return false; +} + +/** + * Build a description of the material we just imported. + * Currently this means a list of the textures present but we + * may eventually want to make it more complete - will be guided + * by what the content creators say they need. + */ +const std::string LLMaterialEditor::buildMaterialDescription() +{ + std::ostringstream desc; + desc << LLTrans::getString("Material Texture Name Header"); + + // add the texture names for each just so long as the material + // we loaded has an entry for it (i think testing the texture + // control UUI for NULL is a valid metric for if it was loaded + // or not but I suspect this code will change a lot so may need + // to revisit + if (!mAlbedoTextureCtrl->getValue().asUUID().isNull()) + { + desc << mAlbedoName; + desc << ", "; + } + if (!mMetallicTextureCtrl->getValue().asUUID().isNull()) + { + desc << mMetallicRoughnessName; + desc << ", "; + } + if (!mEmissiveTextureCtrl->getValue().asUUID().isNull()) + { + desc << mEmissiveName; + desc << ", "; + } + if (!mNormalTextureCtrl->getValue().asUUID().isNull()) + { + desc << mNormalName; + } + + // trim last char if it's a ',' in case there is no normal texture + // present and the code above inserts one + // (no need to check for string length - always has initial string) + std::string::iterator iter = desc.str().end() - 1; + if (*iter == ',') + { + desc.str().erase(iter); + } + + // sanitize the material description so that it's compatible with the inventory + // note: split this up because clang doesn't like operating directly on the + // str() - error: lvalue reference to type 'basic_string<...>' cannot bind to a + // temporary of type 'basic_string<...>' + std::string inv_desc = desc.str(); + LLInventoryObject::correctInventoryName(inv_desc); + + return inv_desc; +} + +bool LLMaterialEditor::saveIfNeeded() +{ + if (mUploadingTexturesCount > 0) + { + // upload already in progress + // wait until textures upload + // will retry saving on callback + return true; + } + + if (saveTextures() > 0) + { + // started texture upload + setEnabled(false); + return true; + } + + std::string buffer = getEncodedAsset(); + + const LLInventoryItem* item = getItem(); + // save it out to database + if (item) + { + if (!saveToInventoryItem(buffer, mItemUUID, mObjectUUID)) + { + return false; + } + + if (mCloseAfterSave) + { + closeFloater(); + } + else + { + mAssetStatus = PREVIEW_ASSET_LOADING; + setEnabled(false); + } + } + else + { //make a new inventory item +#if 1 + // gen a new uuid for this asset + LLTransactionID tid; + tid.generate(); // timestamp-based randomization + uniquification + LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + std::string res_desc = buildMaterialDescription(); + U32 next_owner_perm = LLPermissions::DEFAULT.getMaskNextOwner(); + LLUUID parent = gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL); + const U8 subtype = NO_INV_SUBTYPE; // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ? + + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), parent, tid, mMaterialName, res_desc, + LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, next_owner_perm, + new LLBoostFuncInventoryCallback([output = buffer](LLUUID const& inv_item_id) { + // from reference in LLSettingsVOBase::createInventoryItem()/updateInventoryItem() + LLResourceUploadInfo::ptr_t uploadInfo = + std::make_shared<LLBufferedAssetUploadInfo>( + inv_item_id, + LLAssetType::AT_MATERIAL, + output, + [](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response) { + LL_INFOS("Material") << "inventory item uploaded. item: " << item_id << " asset: " << new_asset_id << " new_item_id: " << new_item_id << " response: " << response << LL_ENDL; + LLSD params = llsd::map("ASSET_ID", new_asset_id); + LLNotificationsUtil::add("MaterialCreated", params); + }); + + // todo: apply permissions from textures here if server doesn't + // if any texture is 'no transfer', material should be 'no transfer' as well + const LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string agent_url(region->getCapability("UpdateMaterialAgentInventory")); + if (agent_url.empty()) + { + LL_ERRS() << "missing required agent inventory cap url" << LL_ENDL; + } + LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo); + } + }) + ); + + // We do not update floater with uploaded asset yet, so just close it. + closeFloater(); +#endif + } + + return true; +} + +// static +bool LLMaterialEditor::saveToInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id) +{ + const LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + LL_WARNS() << "Not connected to a region, cannot save material." << LL_ENDL; + return false; + } + std::string agent_url = region->getCapability("UpdateMaterialAgentInventory"); + std::string task_url = region->getCapability("UpdateMaterialTaskInventory"); + + if (!agent_url.empty() && !task_url.empty()) + { + std::string url; + LLResourceUploadInfo::ptr_t uploadInfo; + + if (task_id.isNull() && !agent_url.empty()) + { + uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(item_id, LLAssetType::AT_MATERIAL, buffer, + [](LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD) { + LLMaterialEditor::finishInventoryUpload(itemId, newAssetId, newItemId); + }); + url = agent_url; + } + else if (!task_id.isNull() && !task_url.empty()) + { + LLUUID object_uuid(task_id); + uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(task_id, item_id, LLAssetType::AT_MATERIAL, buffer, + [object_uuid](LLUUID itemId, LLUUID, LLUUID newAssetId, LLSD) { + LLMaterialEditor::finishTaskUpload(itemId, newAssetId, object_uuid); + }); + url = task_url; + } + + if (!url.empty() && uploadInfo) + { + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } + else + { + return false; + } + + } + else // !gAssetStorage + { + LL_WARNS() << "Not connected to an materials capable region." << LL_ENDL; + return false; + } + + // todo: apply permissions from textures here if server doesn't + // if any texture is 'no transfer', material should be 'no transfer' as well + + return true; +} + +void LLMaterialEditor::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId) +{ + // Update the UI with the new asset. + LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", LLSD(itemId)); + if (me) + { + if (newItemId.isNull()) + { + me->setAssetId(newAssetId); + me->refreshFromInventory(); + } + else if (newItemId.notNull()) + { + // Not supposed to happen? + me->refreshFromInventory(newItemId); + } + else + { + me->refreshFromInventory(itemId); + } + } +} + +void LLMaterialEditor::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId) +{ + LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", LLSD(itemId)); + if (me) + { + me->setAssetId(newAssetId); + me->refreshFromInventory(); + } +} + +void LLMaterialEditor::finishSaveAs(const LLUUID &oldItemId, const LLUUID &newItemId, const std::string &buffer) +{ + LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", LLSD(oldItemId)); + LLViewerInventoryItem* item = gInventory.getItem(newItemId); + if (item) + { + if (me) + { + me->mItemUUID = newItemId; + me->setKey(LLSD(newItemId)); // for findTypedInstance + me->setMaterialName(item->getName()); + if (!saveToInventoryItem(buffer, newItemId, LLUUID::null)) + { + me->setEnabled(true); + } + } + else + { + saveToInventoryItem(buffer, newItemId, LLUUID::null); + } + } + else if (me) + { + me->setEnabled(true); + LL_WARNS() << "Item does not exist" << LL_ENDL; + } +} + +void LLMaterialEditor::refreshFromInventory(const LLUUID& new_item_id) +{ + if (new_item_id.notNull()) + { + mItemUUID = new_item_id; + setKey(LLSD(new_item_id)); + } + LL_DEBUGS() << "LLPreviewNotecard::refreshFromInventory()" << LL_ENDL; + loadAsset(); +} + + +void LLMaterialEditor::onClickSaveAs() +{ + if (!can_afford_transaction(mExpectedUploadCost)) + { + LLSD args; + args["COST"] = llformat("%d", mExpectedUploadCost); + LLNotificationsUtil::add("ErrorCannotAffordUpload", args); + return; + } + + LLSD args; + args["DESC"] = mMaterialName; + + LLNotificationsUtil::add("SaveMaterialAs", args, LLSD(), boost::bind(&LLMaterialEditor::onSaveAsMsgCallback, this, _1, _2)); +} + +void LLMaterialEditor::onSaveAsMsgCallback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + std::string new_name = response["message"].asString(); + LLInventoryObject::correctInventoryName(new_name); + if (!new_name.empty()) + { + const LLInventoryItem* item = getItem(); + if (item) + { + const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + LLUUID parent_id = item->getParentUUID(); + if (mObjectUUID.notNull() || marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getLibraryRootFolderID())) + { + parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL); + } + + // A two step process, first copy an existing item, then create new asset + std::string buffer = getEncodedAsset(); + LLPointer<LLInventoryCallback> cb = new LLMaterialEditorCopiedCallback(buffer, item->getUUID()); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + parent_id, + new_name, + cb); + + mAssetStatus = PREVIEW_ASSET_LOADING; + setEnabled(false); + } + else + { + setMaterialName(new_name); + onClickSave(); + } + } + else + { + LLNotificationsUtil::add("InvalidMaterialName"); + } + } +} + +void LLMaterialEditor::onClickCancel() +{ + if (mHasUnsavedChanges) + { + LLNotificationsUtil::add("UsavedMaterialChanges", LLSD(), LLSD(), boost::bind(&LLMaterialEditor::onCancelMsgCallback, this, _1, _2)); + } + else + { + closeFloater(); + } +} + +void LLMaterialEditor::onCancelMsgCallback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + closeFloater(); + } +} + +class LLMaterialFilePicker : public LLFilePickerThread +{ +public: + LLMaterialFilePicker(); + virtual void notify(const std::vector<std::string>& filenames); + static void textureLoadedCallback(BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata); + +}; + +LLMaterialFilePicker::LLMaterialFilePicker() + : LLFilePickerThread(LLFilePicker::FFLOAD_MATERIAL) +{ +} + +void LLMaterialFilePicker::notify(const std::vector<std::string>& filenames) +{ + if (LLAppViewer::instance()->quitRequested()) + { + return; + } + + + if (filenames.size() > 0) + { + LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor"); + if (me) + { + me->loadMaterialFromFile(filenames[0]); + } + } +} + +static void pack_textures( + LLPointer<LLImageRaw>& albedo_img, + LLPointer<LLImageRaw>& normal_img, + LLPointer<LLImageRaw>& mr_img, + LLPointer<LLImageRaw>& emissive_img, + LLPointer<LLImageRaw>& occlusion_img, + LLPointer<LLImageJ2C>& albedo_j2c, + LLPointer<LLImageJ2C>& normal_j2c, + LLPointer<LLImageJ2C>& mr_j2c, + LLPointer<LLImageJ2C>& emissive_j2c) +{ + if (albedo_img) + { + albedo_j2c = LLViewerTextureList::convertToUploadFile(albedo_img); + } + + if (normal_img) + { + normal_j2c = LLViewerTextureList::convertToUploadFile(normal_img); + } + + if (mr_img) + { + mr_j2c = LLViewerTextureList::convertToUploadFile(mr_img); + } + + if (emissive_img) + { + emissive_j2c = LLViewerTextureList::convertToUploadFile(emissive_img); + } +} + +void LLMaterialFilePicker::textureLoadedCallback(BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata) +{ +} + + +void LLMaterialEditor::loadMaterialFromFile(const std::string& filename) +{ + tinygltf::TinyGLTF loader; + std::string error_msg; + std::string warn_msg; + + bool loaded = false; + tinygltf::Model model_in; + + std::string filename_lc = filename; + LLStringUtil::toLower(filename_lc); + + // Load a tinygltf model fom a file. Assumes that the input filename has already been + // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish. + if (std::string::npos == filename_lc.rfind(".gltf")) + { // file is binary + loaded = loader.LoadBinaryFromFile(&model_in, &error_msg, &warn_msg, filename); + } + else + { // file is ascii + loaded = loader.LoadASCIIFromFile(&model_in, &error_msg, &warn_msg, filename); + } + + if (!loaded) + { + LLNotificationsUtil::add("CannotUploadMaterial"); + return; + } + + if (model_in.materials.empty()) + { + // materials are missing + LLNotificationsUtil::add("CannotUploadMaterial"); + return; + } + + std::string folder = gDirUtilp->getDirName(filename); + + + tinygltf::Material material_in = model_in.materials[0]; + + tinygltf::Model model_out; + model_out.asset.version = "2.0"; + model_out.materials.resize(1); + + // get albedo texture + LLPointer<LLImageRaw> albedo_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.baseColorTexture.index, mAlbedoName); + // get normal map + LLPointer<LLImageRaw> normal_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.normalTexture.index, mNormalName); + // get metallic-roughness texture + LLPointer<LLImageRaw> mr_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.pbrMetallicRoughness.metallicRoughnessTexture.index, mMetallicRoughnessName); + // get emissive texture + LLPointer<LLImageRaw> emissive_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.emissiveTexture.index, mEmissiveName); + // get occlusion map if needed + LLPointer<LLImageRaw> occlusion_img; + if (material_in.occlusionTexture.index != material_in.pbrMetallicRoughness.metallicRoughnessTexture.index) + { + std::string tmp; + occlusion_img = LLTinyGLTFHelper::getTexture(folder, model_in, material_in.occlusionTexture.index, tmp); + } + + LLTinyGLTFHelper::initFetchedTextures(material_in, albedo_img, normal_img, mr_img, emissive_img, occlusion_img, + mAlbedoFetched, mNormalFetched, mMetallicRoughnessFetched, mEmissiveFetched); + pack_textures(albedo_img, normal_img, mr_img, emissive_img, occlusion_img, + mAlbedoJ2C, mNormalJ2C, mMetallicRoughnessJ2C, mEmissiveJ2C); + + LLUUID albedo_id; + if (mAlbedoFetched.notNull()) + { + mAlbedoFetched->forceToSaveRawImage(0, F32_MAX); + albedo_id = mAlbedoFetched->getID(); + + if (mAlbedoName.empty()) + { + mAlbedoName = MATERIAL_ALBEDO_DEFAULT_NAME; + } + } + + LLUUID normal_id; + if (mNormalFetched.notNull()) + { + mNormalFetched->forceToSaveRawImage(0, F32_MAX); + normal_id = mNormalFetched->getID(); + + if (mNormalName.empty()) + { + mNormalName = MATERIAL_NORMAL_DEFAULT_NAME; + } + } + + LLUUID mr_id; + if (mMetallicRoughnessFetched.notNull()) + { + mMetallicRoughnessFetched->forceToSaveRawImage(0, F32_MAX); + mr_id = mMetallicRoughnessFetched->getID(); + + if (mMetallicRoughnessName.empty()) + { + mMetallicRoughnessName = MATERIAL_METALLIC_DEFAULT_NAME; + } + } + + LLUUID emissive_id; + if (mEmissiveFetched.notNull()) + { + mEmissiveFetched->forceToSaveRawImage(0, F32_MAX); + emissive_id = mEmissiveFetched->getID(); + + if (mEmissiveName.empty()) + { + mEmissiveName = MATERIAL_EMISSIVE_DEFAULT_NAME; + } + } + + setAlbedoId(albedo_id); + setAlbedoUploadId(albedo_id); + setMetallicRoughnessId(mr_id); + setMetallicRoughnessUploadId(mr_id); + setEmissiveId(emissive_id); + setEmissiveUploadId(emissive_id); + setNormalId(normal_id); + setNormalUploadId(normal_id); + + setFromGltfModel(model_in); + + setFromGltfMetaData(filename_lc, model_in); + + setHasUnsavedChanges(true); + openFloater(); + + applyToSelection(); +} + +bool LLMaterialEditor::setFromGltfModel(tinygltf::Model& model, bool set_textures) +{ + if (model.materials.size() > 0) + { + tinygltf::Material& material_in = model.materials[0]; + + if (set_textures) + { + S32 index; + LLUUID id; + + // get albedo texture + index = material_in.pbrMetallicRoughness.baseColorTexture.index; + if (index >= 0) + { + id.set(model.images[index].uri); + setAlbedoId(id); + } + else + { + setAlbedoId(LLUUID::null); + } + + // get normal map + index = material_in.normalTexture.index; + if (index >= 0) + { + id.set(model.images[index].uri); + setNormalId(id); + } + else + { + setNormalId(LLUUID::null); + } + + // get metallic-roughness texture + index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index; + if (index >= 0) + { + id.set(model.images[index].uri); + setMetallicRoughnessId(id); + } + else + { + setMetallicRoughnessId(LLUUID::null); + } + + // get emissive texture + index = material_in.emissiveTexture.index; + if (index >= 0) + { + id.set(model.images[index].uri); + setEmissiveId(id); + } + else + { + setEmissiveId(LLUUID::null); + } + } + + setAlphaMode(material_in.alphaMode); + setAlphaCutoff(material_in.alphaCutoff); + + setAlbedoColor(LLTinyGLTFHelper::getColor(material_in.pbrMetallicRoughness.baseColorFactor)); + setEmissiveColor(LLTinyGLTFHelper::getColor(material_in.emissiveFactor)); + + setMetalnessFactor(material_in.pbrMetallicRoughness.metallicFactor); + setRoughnessFactor(material_in.pbrMetallicRoughness.roughnessFactor); + + setDoubleSided(material_in.doubleSided); + } + + return true; +} + +/** + * Build a texture name from the contents of the (in tinyGLFT parlance) + * Image URI. This often is filepath to the original image on the users' + * local file system. + */ +const std::string LLMaterialEditor::getImageNameFromUri(std::string image_uri, const std::string texture_type) +{ + // getBaseFileName() works differently on each platform and file patchs + // can contain both types of delimiter so unify them then extract the + // base name (no path or extension) + std::replace(image_uri.begin(), image_uri.end(), '\\', gDirUtilp->getDirDelimiter()[0]); + std::replace(image_uri.begin(), image_uri.end(), '/', gDirUtilp->getDirDelimiter()[0]); + const bool strip_extension = true; + std::string stripped_uri = gDirUtilp->getBaseFileName(image_uri, strip_extension); + + // sometimes they can be really long and unwieldy - 64 chars is enough for anyone :) + const int max_texture_name_length = 64; + if (stripped_uri.length() > max_texture_name_length) + { + stripped_uri = stripped_uri.substr(0, max_texture_name_length - 1); + } + + // We intend to append the type of texture (albedo, emissive etc.) to the + // name of the texture but sometimes the creator already did that. To try + // to avoid repeats (not perfect), we look for the texture type in the name + // and if we find it, do not append the type, later on. One way this fails + // (and it's fine for now) is I see some texture/image uris have a name like + // "metallic roughness" and of course, that doesn't match our predefined + // name "metallicroughness" - consider fix later.. + bool name_includes_type = false; + std::string stripped_uri_lower = stripped_uri; + LLStringUtil::toLower(stripped_uri_lower); + stripped_uri_lower.erase(std::remove_if(stripped_uri_lower.begin(), stripped_uri_lower.end(), isspace), stripped_uri_lower.end()); + std::string texture_type_lower = texture_type; + LLStringUtil::toLower(texture_type_lower); + texture_type_lower.erase(std::remove_if(texture_type_lower.begin(), texture_type_lower.end(), isspace), texture_type_lower.end()); + if (stripped_uri_lower.find(texture_type_lower) != std::string::npos) + { + name_includes_type = true; + } + + // uri doesn't include the type at all + if (name_includes_type == false) + { + // uri doesn't include the type and the uri is not empty + // so we can include everything + if (stripped_uri.length() > 0) + { + // example "DamagedHelmet: base layer (Albedo)" + return STRINGIZE( + mMaterialNameShort << + ": " << + stripped_uri << + " (" << + texture_type << + ")" + ); + } + else + // uri doesn't include the type (because the uri is empty) + // so we must reorganize the string a bit to include the name + // and an explicit name type + { + // example "DamagedHelmet: (Emissive)" + return STRINGIZE( + mMaterialNameShort << + " (" << + texture_type << + ")" + ); + } + } + else + // uri includes the type so just use it directly with the + // name of the material + { + return STRINGIZE( + // example: AlienBust: normal_layer + mMaterialNameShort << + ": " << + stripped_uri + ); + } +} + +/** + * Update the metadata for the material based on what we find in the loaded + * file (along with some assumptions and interpretations...). Fields include + * the name of the material, a material description and the names of the + * composite textures. + */ +void LLMaterialEditor::setFromGltfMetaData(const std::string& filename, tinygltf::Model& model) +{ + // Use the name (without any path/extension) of the file that was + // uploaded as the base of the material name. Then if the name of the + // scene is present and not blank, append that and use the result as + // the name of the material. This is a first pass at creating a + // naming scheme that is useful to real content creators and hopefully + // avoid 500 materials in your inventory called "scene" or "Default" + const bool strip_extension = true; + std::string base_filename = gDirUtilp->getBaseFileName(filename, strip_extension); + + // Extract the name of the scene. Note it is often blank or some very + // generic name like "Scene" or "Default" so using this in the name + // is less useful than you might imagine. + std::string scene_name; + if (model.scenes.size() > 0) + { + tinygltf::Scene& scene_in = model.scenes[0]; + if (scene_in.name.length()) + { + scene_name = scene_in.name; + } + else + { + // scene name is empty so no point using it + } + } + else + { + // scene name isn't present so no point using it + } + + // If we have a valid scene name, use it to build the short and + // long versions of the material name. The long version is used + // as you might expect, for the material name. The short version is + // used as part of the image/texture name - the theory is that will + // allow content creators to track the material and the corresponding + // textures + if (scene_name.length()) + { + mMaterialNameShort = base_filename; + + mMaterialName = STRINGIZE( + base_filename << + " " << + "(" << + scene_name << + ")" + ); + } + else + // otherwise, just use the trimmed filename as is + { + mMaterialNameShort = base_filename; + mMaterialName = base_filename; + } + + // sanitize the material name so that it's compatible with the inventory + LLInventoryObject::correctInventoryName(mMaterialName); + LLInventoryObject::correctInventoryName(mMaterialNameShort); + + // We also set the title of the floater to match the + // name of the material + setTitle(mMaterialName); + + /** + * Extract / derive the names of each composite texture. For each, the + * index in the first material (we only support 1 material currently) is + * used to to determine which of the "Images" is used. If the index is -1 + * then that texture type is not present in the material (Seems to be + * quite common that a material is missing 1 or more types of texture) + */ + if (model.materials.size() > 0) + { + const tinygltf::Material& first_material = model.materials[0]; + + mAlbedoName = MATERIAL_ALBEDO_DEFAULT_NAME; + // note: unlike the other textures, albedo doesn't have its own entry + // in the tinyGLTF Material struct. Rather, it is taken from a + // sub-texture in the pbrMetallicRoughness member + int index = first_material.pbrMetallicRoughness.baseColorTexture.index; + if (index > -1 && index < model.images.size()) + { + // sanitize the name we decide to use for each texture + std::string texture_name = getImageNameFromUri(model.images[index].uri, MATERIAL_ALBEDO_DEFAULT_NAME); + LLInventoryObject::correctInventoryName(texture_name); + mAlbedoName = texture_name; + } + + mEmissiveName = MATERIAL_EMISSIVE_DEFAULT_NAME; + index = first_material.emissiveTexture.index; + if (index > -1 && index < model.images.size()) + { + std::string texture_name = getImageNameFromUri(model.images[index].uri, MATERIAL_EMISSIVE_DEFAULT_NAME); + LLInventoryObject::correctInventoryName(texture_name); + mEmissiveName = texture_name; + } + + mMetallicRoughnessName = MATERIAL_METALLIC_DEFAULT_NAME; + index = first_material.pbrMetallicRoughness.metallicRoughnessTexture.index; + if (index > -1 && index < model.images.size()) + { + std::string texture_name = getImageNameFromUri(model.images[index].uri, MATERIAL_METALLIC_DEFAULT_NAME); + LLInventoryObject::correctInventoryName(texture_name); + mMetallicRoughnessName = texture_name; + } + + mNormalName = MATERIAL_NORMAL_DEFAULT_NAME; + index = first_material.normalTexture.index; + if (index > -1 && index < model.images.size()) + { + std::string texture_name = getImageNameFromUri(model.images[index].uri, MATERIAL_NORMAL_DEFAULT_NAME); + LLInventoryObject::correctInventoryName(texture_name); + mNormalName = texture_name; + } + } +} + +void LLMaterialEditor::importMaterial() +{ + (new LLMaterialFilePicker())->getFile(); +} + +class LLRemderMaterialFunctor : public LLSelectedTEFunctor +{ +public: + LLRemderMaterialFunctor(LLGLTFMaterial *mat, const LLUUID &id) + : mMat(mat), mMatId(id) + { + } + + virtual bool apply(LLViewerObject* objectp, S32 te) + { + if (objectp && objectp->permModify() && objectp->getVolume()) + { + LLVOVolume* vobjp = (LLVOVolume*)objectp; + vobjp->setRenderMaterialID(te, mMatId); + vobjp->getTE(te)->setGLTFMaterial(mMat); + vobjp->updateTEMaterialTextures(te); + } + return true; + } +private: + LLPointer<LLGLTFMaterial> mMat; + LLUUID mMatId; +}; + +void LLMaterialEditor::applyToSelection() +{ + LLPointer<LLGLTFMaterial> mat = new LLGLTFMaterial(); + getGLTFMaterial(mat); + const LLUUID placeholder("984e183e-7811-4b05-a502-d79c6f978a98"); + LLUUID asset_id = mAssetID.notNull() ? mAssetID : placeholder; + LLRemderMaterialFunctor mat_func(mat, asset_id); + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + selected_objects->applyToTEs(&mat_func); +} + +void LLMaterialEditor::getGLTFMaterial(LLGLTFMaterial* mat) +{ + mat->mAlbedoColor = getAlbedoColor(); + mat->mAlbedoColor.mV[3] = getTransparency(); + mat->mAlbedoId = getAlbedoId(); + + mat->mNormalId = getNormalId(); + + mat->mMetallicRoughnessId = getMetallicRoughnessId(); + mat->mMetallicFactor = getMetalnessFactor(); + mat->mRoughnessFactor = getRoughnessFactor(); + + mat->mEmissiveColor = getEmissiveColor(); + mat->mEmissiveId = getEmissiveId(); + + mat->mDoubleSided = getDoubleSided(); + mat->setAlphaMode(getAlphaMode()); +} + +void LLMaterialEditor::setFromGLTFMaterial(LLGLTFMaterial* mat) +{ + setAlbedoColor(mat->mAlbedoColor); + setAlbedoId(mat->mAlbedoId); + setNormalId(mat->mNormalId); + + setMetallicRoughnessId(mat->mMetallicRoughnessId); + setMetalnessFactor(mat->mMetallicFactor); + setRoughnessFactor(mat->mRoughnessFactor); + + setEmissiveColor(mat->mEmissiveColor); + setEmissiveId(mat->mEmissiveId); + + setDoubleSided(mat->mDoubleSided); + setAlphaMode(mat->getAlphaMode()); +} + +void LLMaterialEditor::loadAsset() +{ + // derived from LLPreviewNotecard::loadAsset + + // TODO: see commented out "editor" references and make them do something appropriate to the UI + + // request the asset. + const LLInventoryItem* item = getItem(); + + bool fail = false; + + if (item) + { + LLPermissions perm(item->getPermissions()); + BOOL allow_copy = gAgent.allowOperation(PERM_COPY, perm, GP_OBJECT_MANIPULATE); + BOOL allow_modify = canModify(mObjectUUID, item); + BOOL source_library = mObjectUUID.isNull() && gInventory.isObjectDescendentOf(mItemUUID, gInventory.getLibraryRootFolderID()); + + setCanSaveAs(allow_copy); + setCanSave(allow_modify && !source_library); + setMaterialName(item->getName()); + + { + mAssetID = item->getAssetUUID(); + if (mAssetID.isNull()) + { + mAssetStatus = PREVIEW_ASSET_LOADED; + setHasUnsavedChanges(false); + } + else + { + LLHost source_sim = LLHost(); + LLSD* user_data = new LLSD(); + + if (mObjectUUID.notNull()) + { + LLViewerObject* objectp = gObjectList.findObject(mObjectUUID); + if (objectp && objectp->getRegion()) + { + source_sim = objectp->getRegion()->getHost(); + } + else + { + // The object that we're trying to look at disappeared, bail. + LL_WARNS() << "Can't find object " << mObjectUUID << " associated with notecard." << LL_ENDL; + mAssetID.setNull(); + mAssetStatus = PREVIEW_ASSET_LOADED; + setHasUnsavedChanges(false); + return; + } + user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID); + } + else + { + user_data = new LLSD(mItemUUID); + } + + gAssetStorage->getInvItemAsset(source_sim, + gAgent.getID(), + gAgent.getSessionID(), + item->getPermissions().getOwner(), + mObjectUUID, + item->getUUID(), + item->getAssetUUID(), + item->getType(), + &onLoadComplete, + (void*)user_data, + TRUE); + mAssetStatus = PREVIEW_ASSET_LOADING; + } + } + } + else if (mObjectUUID.notNull() && mItemUUID.notNull()) + { + LLViewerObject* objectp = gObjectList.findObject(mObjectUUID); + if (objectp && (objectp->isInventoryPending() || objectp->isInventoryDirty())) + { + // It's a material in object's inventory and we failed to get it because inventory is not up to date. + // Subscribe for callback and retry at inventoryChanged() + registerVOInventoryListener(objectp, NULL); //removes previous listener + + if (objectp->isInventoryDirty()) + { + objectp->requestInventory(); + } + } + else + { + fail = true; + } + } + else + { + fail = true; + } + + if (fail) + { + /*editor->setText(LLStringUtil::null); + editor->makePristine(); + editor->setEnabled(TRUE);*/ + // Don't set asset status here; we may not have set the item id yet + // (e.g. when this gets called initially) + //mAssetStatus = PREVIEW_ASSET_LOADED; + } +} + +// static +void LLMaterialEditor::onLoadComplete(const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LL_INFOS() << "LLMaterialEditor::onLoadComplete()" << LL_ENDL; + LLSD* floater_key = (LLSD*)user_data; + LLMaterialEditor* editor = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", *floater_key); + if (editor) + { + if (0 == status) + { + LLFileSystem file(asset_uuid, type, LLFileSystem::READ); + + S32 file_length = file.getSize(); + + std::vector<char> buffer(file_length + 1); + file.read((U8*)&buffer[0], file_length); + + editor->decodeAsset(buffer); + + BOOL modifiable = editor->canModify(editor->mObjectID, editor->getItem()); + editor->setEnabled(modifiable); + editor->setHasUnsavedChanges(false); + editor->mAssetStatus = PREVIEW_ASSET_LOADED; + } + else + { + if (LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + LL_ERR_FILE_EMPTY == status) + { + LLNotificationsUtil::add("MaterialMissing"); + } + else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) + { + LLNotificationsUtil::add("MaterialNoPermissions"); + } + else + { + LLNotificationsUtil::add("UnableToLoadMaterial"); + } + + LL_WARNS() << "Problem loading material: " << status << LL_ENDL; + editor->mAssetStatus = PREVIEW_ASSET_ERROR; + } + } + delete floater_key; +} + +void LLMaterialEditor::inventoryChanged(LLViewerObject* object, + LLInventoryObject::object_list_t* inventory, + S32 serial_num, + void* user_data) +{ + removeVOInventoryListener(); + loadAsset(); +} + + +void LLMaterialEditor::saveTexture(LLImageJ2C* img, const std::string& name, const LLUUID& asset_id, upload_callback_f cb) +{ + if (asset_id.isNull() + || img == nullptr + || img->getDataSize() == 0) + { + return; + } + + // copy image bytes into string + std::string buffer; + buffer.assign((const char*) img->getData(), img->getDataSize()); + + U32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); + + + LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>( + buffer, + asset_id, + name, + name, + 0, + LLFolderType::FT_TEXTURE, + LLInventoryType::IT_TEXTURE, + LLAssetType::AT_TEXTURE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost, + false, + cb)); + + upload_new_resource(uploadInfo); +} + +S32 LLMaterialEditor::saveTextures() +{ + S32 work_count = 0; + LLSD key = getKey(); // must be locally declared for lambda's capture to work + if (mAlbedoTextureUploadId == getAlbedoId() && mAlbedoTextureUploadId.notNull()) + { + mUploadingTexturesCount++; + work_count++; + saveTexture(mAlbedoJ2C, mAlbedoName, mAlbedoTextureUploadId, [key](LLUUID newAssetId, LLSD response) + { + LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", key); + if (me) + { + if (response["success"].asBoolean()) + { + me->setAlbedoId(newAssetId); + } + else + { + // To make sure that we won't retry (some failures can cb immediately) + me->setAlbedoId(LLUUID::null); + } + me->mUploadingTexturesCount--; + + // try saving + me->saveIfNeeded(); + } + }); + } + if (mNormalTextureUploadId == getNormalId() && mNormalTextureUploadId.notNull()) + { + mUploadingTexturesCount++; + work_count++; + saveTexture(mNormalJ2C, mNormalName, mNormalTextureUploadId, [key](LLUUID newAssetId, LLSD response) + { + LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", key); + if (me) + { + if (response["success"].asBoolean()) + { + me->setNormalId(newAssetId); + } + else + { + me->setNormalId(LLUUID::null); + } + me->setNormalId(newAssetId); + me->mUploadingTexturesCount--; + + // try saving + me->saveIfNeeded(); + } + }); + } + if (mMetallicTextureUploadId == getMetallicRoughnessId() && mMetallicTextureUploadId.notNull()) + { + mUploadingTexturesCount++; + work_count++; + saveTexture(mMetallicRoughnessJ2C, mMetallicRoughnessName, mMetallicTextureUploadId, [key](LLUUID newAssetId, LLSD response) + { + LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", key); + if (me) + { + if (response["success"].asBoolean()) + { + me->setMetallicRoughnessId(newAssetId); + } + else + { + me->setMetallicRoughnessId(LLUUID::null); + } + me->mUploadingTexturesCount--; + + // try saving + me->saveIfNeeded(); + } + }); + } + + if (mEmissiveTextureUploadId == getEmissiveId() && mEmissiveTextureUploadId.notNull()) + { + mUploadingTexturesCount++; + work_count++; + saveTexture(mEmissiveJ2C, mEmissiveName, mEmissiveTextureUploadId, [key](LLUUID newAssetId, LLSD response) + { + LLMaterialEditor* me = LLFloaterReg::findTypedInstance<LLMaterialEditor>("material_editor", LLSD(key)); + if (me) + { + if (response["success"].asBoolean()) + { + me->setEmissiveId(newAssetId); + } + else + { + me->setEmissiveId(LLUUID::null); + } + me->mUploadingTexturesCount--; + + // try saving + me->saveIfNeeded(); + } + }); + } + + // discard upload buffers once textures have been saved + mAlbedoJ2C = nullptr; + mNormalJ2C = nullptr; + mEmissiveJ2C = nullptr; + mMetallicRoughnessJ2C = nullptr; + + mAlbedoFetched = nullptr; + mNormalFetched = nullptr; + mMetallicRoughnessFetched = nullptr; + mEmissiveFetched = nullptr; + + mAlbedoTextureUploadId.setNull(); + mNormalTextureUploadId.setNull(); + mMetallicTextureUploadId.setNull(); + mEmissiveTextureUploadId.setNull(); + + // asset storage can callback immediately, causing a decrease + // of mUploadingTexturesCount, report amount of work scheduled + // not amount of work remaining + return work_count; +} + diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h new file mode 100644 index 0000000000..59ae00e565 --- /dev/null +++ b/indra/newview/llmaterialeditor.h @@ -0,0 +1,213 @@ +/** + * @file llmaterialeditor.h + * @brief LLMaterialEditor class header file + * + * $LicenseInfo:firstyear=2022&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$ + */ + +#pragma once + +#include "llpreview.h" +#include "llvoinventorylistener.h" +#include "llimagej2c.h" +#include "llviewertexture.h" + +class LLTextureCtrl; + +namespace tinygltf +{ + class Model; +} + +class LLGLTFMaterial; + +class LLMaterialEditor : public LLPreview, public LLVOInventoryListener +{ +public: + LLMaterialEditor(const LLSD& key); + + bool setFromGltfModel(tinygltf::Model& model, bool set_textures = false); + + void setFromGltfMetaData(const std::string& filename, tinygltf::Model& model); + + // open a file dialog and select a gltf/glb file for import + static void importMaterial(); + + // for live preview, apply current material to currently selected object + void applyToSelection(); + + void getGLTFMaterial(LLGLTFMaterial* mat); + + void setFromGLTFMaterial(LLGLTFMaterial* mat); + + void loadAsset() override; + void loadMaterialFromFile(const std::string& filename); + + static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); + + void inventoryChanged(LLViewerObject* object, LLInventoryObject::object_list_t* inventory, S32 serial_num, void* user_data) override; + + typedef std::function<void(LLUUID newAssetId, LLSD response)> upload_callback_f; + void saveTexture(LLImageJ2C* img, const std::string& name, const LLUUID& asset_id, upload_callback_f cb); + + // save textures to inventory if needed + // returns amount of scheduled uploads + S32 saveTextures(); + + void onClickSave(); + + // get a dump of the json representation of the current state of the editor UI in GLTF format + std::string getGLTFJson(bool prettyprint = true); + + void getGLBData(std::vector<U8>& data); + + void getGLTFModel(tinygltf::Model& model); + + std::string getEncodedAsset(); + + bool decodeAsset(const std::vector<char>& buffer); + + bool saveIfNeeded(); + static bool saveToInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id); + + static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId); + + static void finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId); + + static void finishSaveAs(const LLUUID &oldItemId, const LLUUID &newItemId, const std::string &buffer); + + void refreshFromInventory(const LLUUID& new_item_id = LLUUID::null); + + void onClickSaveAs(); + void onSaveAsMsgCallback(const LLSD& notification, const LLSD& response); + void onClickCancel(); + void onCancelMsgCallback(const LLSD& notification, const LLSD& response); + + // llpanel + BOOL postBuild() override; + void onClickCloseBtn(bool app_quitting = false) override; + + void onClose(bool app_quitting) override; + + LLUUID getAlbedoId(); + void setAlbedoId(const LLUUID& id); + void setAlbedoUploadId(const LLUUID& id); + + LLColor4 getAlbedoColor(); + + // sets both albedo color and transparency + void setAlbedoColor(const LLColor4& color); + + F32 getTransparency(); + void setTransparency(F32 transparency); + + std::string getAlphaMode(); + void setAlphaMode(const std::string& alpha_mode); + + F32 getAlphaCutoff(); + void setAlphaCutoff(F32 alpha_cutoff); + + void setMaterialName(const std::string &name); + + LLUUID getMetallicRoughnessId(); + void setMetallicRoughnessId(const LLUUID& id); + void setMetallicRoughnessUploadId(const LLUUID& id); + + F32 getMetalnessFactor(); + void setMetalnessFactor(F32 factor); + + F32 getRoughnessFactor(); + void setRoughnessFactor(F32 factor); + + LLUUID getEmissiveId(); + void setEmissiveId(const LLUUID& id); + void setEmissiveUploadId(const LLUUID& id); + + LLColor4 getEmissiveColor(); + void setEmissiveColor(const LLColor4& color); + + LLUUID getNormalId(); + void setNormalId(const LLUUID& id); + void setNormalUploadId(const LLUUID& id); + + bool getDoubleSided(); + void setDoubleSided(bool double_sided); + + void setHasUnsavedChanges(bool value); + void setCanSaveAs(BOOL value); + void setCanSave(BOOL value); + + void onCommitAlbedoTexture(LLUICtrl* ctrl, const LLSD& data); + void onCommitMetallicTexture(LLUICtrl* ctrl, const LLSD& data); + void onCommitEmissiveTexture(LLUICtrl* ctrl, const LLSD& data); + void onCommitNormalTexture(LLUICtrl* ctrl, const LLSD& data); + +private: + friend class LLMaterialFilePicker; + + LLUUID mAssetID; + LLUUID mObjectID; + + LLTextureCtrl* mAlbedoTextureCtrl; + LLTextureCtrl* mMetallicTextureCtrl; + LLTextureCtrl* mEmissiveTextureCtrl; + LLTextureCtrl* mNormalTextureCtrl; + + // 'Default' texture, unless it's null or from inventory is the one with the fee + LLUUID mAlbedoTextureUploadId; + LLUUID mMetallicTextureUploadId; + LLUUID mEmissiveTextureUploadId; + LLUUID mNormalTextureUploadId; + + // last known name of each texture + std::string mAlbedoName; + std::string mNormalName; + std::string mMetallicRoughnessName; + std::string mEmissiveName; + + // keep pointers to fetched textures or viewer will remove them + // if user temporary selects something else with 'apply now' + LLPointer<LLViewerFetchedTexture> mAlbedoFetched; + LLPointer<LLViewerFetchedTexture> mNormalFetched; + LLPointer<LLViewerFetchedTexture> mMetallicRoughnessFetched; + LLPointer<LLViewerFetchedTexture> mEmissiveFetched; + + // J2C versions of packed buffers for uploading + LLPointer<LLImageJ2C> mAlbedoJ2C; + LLPointer<LLImageJ2C> mNormalJ2C; + LLPointer<LLImageJ2C> mMetallicRoughnessJ2C; + LLPointer<LLImageJ2C> mEmissiveJ2C; + + // utility function for converting image uri into a texture name + const std::string getImageNameFromUri(std::string image_uri, const std::string texture_type); + + // utility function for building a description of the imported material + // based on what we know about it. + const std::string buildMaterialDescription(); + + bool mHasUnsavedChanges; + S32 mUploadingTexturesCount; + S32 mExpectedUploadCost; + std::string mMaterialNameShort; + std::string mMaterialName; +}; + diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 859d987fc3..c3fbada9db 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -30,6 +30,7 @@ #include "llmodelloader.h" #include "lldaeloader.h" +#include "llgltfloader.h" #include "llfloatermodelpreview.h" #include "llagent.h" @@ -732,20 +733,41 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable std::map<std::string, std::string> joint_alias_map; getJointAliases(joint_alias_map); - mModelLoader = new LLDAELoader( - filename, - lod, - &LLModelPreview::loadedCallback, - &LLModelPreview::lookupJointByName, - &LLModelPreview::loadTextures, - &LLModelPreview::stateChangedCallback, - this, - mJointTransformMap, - mJointsFromNode, - joint_alias_map, - LLSkinningUtil::getMaxJointCount(), - gSavedSettings.getU32("ImporterModelLimit"), - gSavedSettings.getBOOL("ImporterPreprocessDAE")); + // three possible file extensions, .dae .gltf .glb + // check for .dae and if not then assume one of the .gl?? + if (std::string::npos != filename.rfind(".dae")) + { + mModelLoader = new LLDAELoader( + filename, + lod, + &LLModelPreview::loadedCallback, + &LLModelPreview::lookupJointByName, + &LLModelPreview::loadTextures, + &LLModelPreview::stateChangedCallback, + this, + mJointTransformMap, + mJointsFromNode, + joint_alias_map, + LLSkinningUtil::getMaxJointCount(), + gSavedSettings.getU32("ImporterModelLimit"), + gSavedSettings.getBOOL("ImporterPreprocessDAE")); + } + else + { + mModelLoader = new LLGLTFLoader( + filename, + lod, + &LLModelPreview::loadedCallback, + &LLModelPreview::lookupJointByName, + &LLModelPreview::loadTextures, + &LLModelPreview::stateChangedCallback, + this, + mJointTransformMap, + mJointsFromNode, + joint_alias_map, + LLSkinningUtil::getMaxJointCount(), + gSavedSettings.getU32("ImporterModelLimit")); + } if (force_disable_slm) { @@ -816,8 +838,10 @@ void LLModelPreview::clearIncompatible(S32 lod) // at this point we don't care about sub-models, // different amount of sub-models means face count mismatch, not incompatibility U32 lod_size = countRootModels(mModel[lod]); + bool replaced_base_model = (lod == LLModel::LOD_HIGH); for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { //clear out any entries that aren't compatible with this model + { + // Clear out any entries that aren't compatible with this model if (i != lod) { if (countRootModels(mModel[i]) != lod_size) @@ -831,9 +855,47 @@ void LLModelPreview::clearIncompatible(S32 lod) mBaseModel = mModel[lod]; mBaseScene = mScene[lod]; mVertexBuffer[5].clear(); + replaced_base_model = true; + } + } + } + } + + if (replaced_base_model && !mGenLOD) + { + // In case base was replaced, we might need to restart generation + + // Check if already started + bool subscribe_for_generation = mLodsQuery.empty(); + + // Remove previously scheduled work + mLodsQuery.clear(); + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (!fmp) return; + + // Schedule new work + for (S32 i = LLModel::LOD_HIGH; i >= 0; --i) + { + if (mModel[i].empty()) + { + // Base model was replaced, regenerate this lod if applicable + LLComboBox* lod_combo = mFMP->findChild<LLComboBox>("lod_source_" + lod_name[i]); + if (!lod_combo) return; + + S32 lod_mode = lod_combo->getCurrentIndex(); + if (lod_mode != LOD_FROM_FILE) + { + mLodsQuery.push_back(i); } } } + + // Subscribe if we have pending work and not subscribed yet + if (!mLodsQuery.empty() && subscribe_for_generation) + { + doOnIdleRepeating(lodQueryCallback); + } } } @@ -1221,8 +1283,9 @@ void LLModelPreview::restoreNormals() // Runs per object, but likely it is a better way to run per model+submodels // returns a ratio of base model indices to resulting indices // returns -1 in case of failure -F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy) +F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, eSimplificationMode simplification_mode) { + // I. Weld faces together // Figure out buffer size S32 size_indices = 0; S32 size_vertices = 0; @@ -1257,20 +1320,21 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe { const LLVolumeFace &face = base_model->getVolumeFace(face_idx); - // vertices + // Vertices S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes); - // normals + // Normals LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes); - // tex coords + // Tex coords copy_bytes = face.mNumVertices * sizeof(LLVector2); memcpy((void*)(combined_tex_coords + combined_positions_shift), (void*)face.mTexCoords, copy_bytes); combined_positions_shift += face.mNumVertices; - // indices, sadly can't do dumb memcpy for indices, need to adjust each value + // Indices + // Sadly can't do dumb memcpy for indices, need to adjust each value for (S32 i = 0; i < face.mNumIndices; ++i) { U16 idx = face.mIndices[i]; @@ -1281,10 +1345,42 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe indices_idx_shift += face.mNumVertices; } - // Now that we have buffers, optimize + // II. Generate a shadow buffer if nessesary. + // Welds together vertices if possible + + U32* shadow_indices = NULL; + // if MESH_OPTIMIZER_FULL, just leave as is, since generateShadowIndexBufferU32 + // won't do anything new, model was remaped on a per face basis. + // Similar for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless + // since 'simplifySloppy' ignores all topology, including normals and uvs. + // Note: simplifySloppy can affect UVs significantly. + if (simplification_mode == MESH_OPTIMIZER_NO_NORMALS) + { + // strip normals, reflections should restore relatively correctly + shadow_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); + LLMeshOptimizer::generateShadowIndexBufferU32(shadow_indices, combined_indices, size_indices, combined_positions, NULL, combined_tex_coords, size_vertices); + } + if (simplification_mode == MESH_OPTIMIZER_NO_UVS) + { + // strip uvs, can heavily affect textures + shadow_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); + LLMeshOptimizer::generateShadowIndexBufferU32(shadow_indices, combined_indices, size_indices, combined_positions, NULL, NULL, size_vertices); + } + + U32* source_indices = NULL; + if (shadow_indices) + { + source_indices = shadow_indices; + } + else + { + source_indices = combined_indices; + } + + // III. Simplify S32 target_indices = 0; F32 result_error = 0; // how far from original the model is, 1 == 100% - S32 new_indices = 0; + S32 size_new_indices = 0; if (indices_decimator > 0) { @@ -1294,38 +1390,43 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe { target_indices = 3; } - new_indices = LLMeshOptimizer::simplifyU32( + + size_new_indices = LLMeshOptimizer::simplifyU32( output_indices, - combined_indices, + source_indices, size_indices, combined_positions, size_vertices, LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], target_indices, error_threshold, - sloppy, + simplification_mode == MESH_OPTIMIZER_NO_TOPOLOGY, &result_error); - if (result_error < 0) { LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel << " target Indices: " << target_indices - << " new Indices: " << new_indices + << " new Indices: " << size_new_indices << " original count: " << size_indices << LL_ENDL; } - if (new_indices < 3) + // free unused buffers + ll_aligned_free_32(combined_indices); + ll_aligned_free_32(shadow_indices); + combined_indices = NULL; + shadow_indices = NULL; + + if (size_new_indices < 3) { // Model should have at least one visible triangle ll_aligned_free<64>(combined_positions); ll_aligned_free_32(output_indices); - ll_aligned_free_32(combined_indices); return -1; } - // repack back into individual faces + // IV. Repack back into individual faces LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); LLVector4a* buffer_normals = buffer_positions + size_vertices; @@ -1356,7 +1457,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe } // Copy relevant indices and vertices - for (S32 i = 0; i < new_indices; ++i) + for (S32 i = 0; i < size_new_indices; ++i) { U32 idx = output_indices[i]; @@ -1379,19 +1480,19 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for" << " model " << target_model->mLabel << " target Indices: " << target_indices - << " new Indices: " << new_indices + << " new Indices: " << size_new_indices << " original count: " << size_indices << " error treshold: " << error_threshold << LL_ENDL; // U16 vertices overflow shouldn't happen, but just in case - new_indices = 0; + size_new_indices = 0; valid_faces = 0; for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx) { - genMeshOptimizerPerFace(base_model, target_model, face_idx, indices_decimator, error_threshold, false); + genMeshOptimizerPerFace(base_model, target_model, face_idx, indices_decimator, error_threshold, simplification_mode); const LLVolumeFace &face = target_model->getVolumeFace(face_idx); - new_indices += face.mNumIndices; + size_new_indices += face.mNumIndices; if (face.mNumIndices >= 3) { valid_faces++; @@ -1399,7 +1500,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe } if (valid_faces) { - return (F32)size_indices / (F32)new_indices; + return (F32)size_indices / (F32)size_new_indices; } else { @@ -1469,18 +1570,17 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe ll_aligned_free<64>(buffer_positions); ll_aligned_free_32(output_indices); ll_aligned_free_16(buffer_indices); - ll_aligned_free_32(combined_indices); - if (new_indices < 3 || valid_faces == 0) + if (size_new_indices < 3 || valid_faces == 0) { // Model should have at least one visible triangle return -1; } - return (F32)size_indices / (F32)new_indices; + return (F32)size_indices / (F32)size_new_indices; } -F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, bool sloppy) +F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, eSimplificationMode simplification_mode) { const LLVolumeFace &face = base_model->getVolumeFace(face_idx); S32 size_indices = face.mNumIndices; @@ -1488,14 +1588,40 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target { return -1; } - // todo: do not allocate per each face, add one large buffer somewhere - // faces have limited amount of indices + S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF; - U16* output = (U16*)ll_aligned_malloc_16(size); + U16* output_indices = (U16*)ll_aligned_malloc_16(size); + + U16* shadow_indices = NULL; + // if MESH_OPTIMIZER_FULL, just leave as is, since generateShadowIndexBufferU32 + // won't do anything new, model was remaped on a per face basis. + // Similar for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless + // since 'simplifySloppy' ignores all topology, including normals and uvs. + if (simplification_mode == MESH_OPTIMIZER_NO_NORMALS) + { + U16* shadow_indices = (U16*)ll_aligned_malloc_16(size); + LLMeshOptimizer::generateShadowIndexBufferU16(shadow_indices, face.mIndices, size_indices, face.mPositions, NULL, face.mTexCoords, face.mNumVertices); + } + if (simplification_mode == MESH_OPTIMIZER_NO_UVS) + { + U16* shadow_indices = (U16*)ll_aligned_malloc_16(size); + LLMeshOptimizer::generateShadowIndexBufferU16(shadow_indices, face.mIndices, size_indices, face.mPositions, NULL, NULL, face.mNumVertices); + } + // Don't run ShadowIndexBuffer for MESH_OPTIMIZER_NO_TOPOLOGY, it's pointless + + U16* source_indices = NULL; + if (shadow_indices) + { + source_indices = shadow_indices; + } + else + { + source_indices = face.mIndices; + } S32 target_indices = 0; F32 result_error = 0; // how far from original the model is, 1 == 100% - S32 new_indices = 0; + S32 size_new_indices = 0; if (indices_decimator > 0) { @@ -1505,25 +1631,25 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target { target_indices = 3; } - new_indices = LLMeshOptimizer::simplify( - output, - face.mIndices, + + size_new_indices = LLMeshOptimizer::simplify( + output_indices, + source_indices, size_indices, face.mPositions, face.mNumVertices, LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], target_indices, error_threshold, - sloppy, + simplification_mode == MESH_OPTIMIZER_NO_TOPOLOGY, &result_error); - if (result_error < 0) { LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx << " of model " << target_model->mLabel << " target Indices: " << target_indices - << " new Indices: " << new_indices + << " new Indices: " << size_new_indices << " original count: " << size_indices << " error treshold: " << error_threshold << LL_ENDL; @@ -1534,10 +1660,9 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target // Copy old values new_face = face; - - if (new_indices < 3) + if (size_new_indices < 3) { - if (!sloppy) + if (simplification_mode != MESH_OPTIMIZER_NO_TOPOLOGY) { // meshopt_optimizeSloppy() can optimize triangles away even if target_indices is > 2, // but optimize() isn't supposed to @@ -1561,23 +1686,24 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target else { // Assign new values - new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output - S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); + new_face.resizeIndices(size_new_indices); // will wipe out mIndices, so new_face can't substitute output + S32 idx_size = (size_new_indices * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output_indices, idx_size); - // clear unused values + // Clear unused values new_face.optimize(); } - ll_aligned_free_16(output); + ll_aligned_free_16(output_indices); + ll_aligned_free_16(shadow_indices); - if (new_indices < 3) + if (size_new_indices < 3) { // At least one triangle is needed return -1; } - return (F32)size_indices / (F32)new_indices; + return (F32)size_indices / (F32)size_new_indices; } void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit) @@ -1711,16 +1837,19 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // Ideally this should run not per model, // but combine all submodels with origin model as well - if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE) + if (model_meshopt_mode == MESH_OPTIMIZER_PRECISE) { - // Run meshoptimizer for each model/object, up to 8 faces in one model. - - // Ideally this should run not per model, - // but combine all submodels with origin model as well - F32 res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); - if (res < 0) + // Run meshoptimizer for each face + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - target_model->copyVolumeFaces(base); + F32 res = genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL); + if (res < 0) + { + // Mesh optimizer failed and returned an invalid model + const LLVolumeFace &face = base->getVolumeFace(face_idx); + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + new_face = face; + } } } @@ -1729,19 +1858,29 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // Run meshoptimizer for each face for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true) < 0) + if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY) < 0) { // Sloppy failed and returned an invalid model - genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); + genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL); } } } if (model_meshopt_mode == MESH_OPTIMIZER_AUTO) { - // Switches between 'combine' method and 'sloppy' based on combine's result. - F32 allowed_ratio_drift = 2.f; - F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + // Remove progressively more data if we can't reach the target. + F32 allowed_ratio_drift = 1.8f; + F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL); + + if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator)) + { + precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_NORMALS); + } + + if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator)) + { + precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_UVS); + } if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator)) { @@ -1749,10 +1888,11 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // Sloppy variant can fail entirely and has issues with precision, // so code needs to do multiple attempts with different decimators. // Todo: this is a bit of a mess, needs to be refined and improved + F32 last_working_decimator = 0.f; F32 last_working_ratio = F32_MAX; - F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); + F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY); if (sloppy_ratio > 0) { @@ -1775,13 +1915,13 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d // side due to overal lack of precision, and we don't need an ideal result, which // likely does not exist, just a better one, so a partial correction is enough. F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2; - sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true); + sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY); } if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio) { // Compensation didn't work, return back to previous decimator - sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); + sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY); } if (sloppy_ratio < 0) @@ -1814,7 +1954,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d && sloppy_decimator > precise_ratio && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case { - sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true); + sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY); sloppy_decimator = sloppy_decimator / sloppy_decimation_step; } } @@ -1834,7 +1974,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d else { // Fallback to normal method - precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_FULL); } LL_INFOS() << "Model " << target_model->getName() @@ -3745,7 +3885,7 @@ bool LLModelPreview::lodQueryCallback() } // return false to continue cycle - return false; + return preview->mLodsQuery.empty(); } } // nothing to process diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 9e32215e6a..215f44357f 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -125,7 +125,7 @@ public: { LOD_FROM_FILE = 0, MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face - MESH_OPTIMIZER_COMBINE, // combines faces into a single model, simplifies, then splits back into faces + MESH_OPTIMIZER_PRECISE, // combines faces into a single model, simplifies, then splits back into faces MESH_OPTIMIZER_SLOPPY, // uses sloppy method, works per face USE_LOD_ABOVE, } eLoDMode; @@ -225,13 +225,21 @@ private: // Count amount of original models, excluding sub-models static U32 countRootModels(LLModelLoader::model_list models); + typedef enum + { + MESH_OPTIMIZER_FULL, + MESH_OPTIMIZER_NO_NORMALS, + MESH_OPTIMIZER_NO_UVS, + MESH_OPTIMIZER_NO_TOPOLOGY, + } eSimplificationMode; + // Merges faces into single mesh, simplifies using mesh optimizer, // then splits back into faces. // Returns reached simplification ratio. -1 in case of a failure. - F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, bool sloppy); + F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode); // Simplifies specified face using mesh optimizer. // Returns reached simplification ratio. -1 in case of a failure. - F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, bool sloppy); + F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, eSimplificationMode simplification_mode); protected: friend class LLModelLoader; diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 4febb72c6c..de94da290d 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1177,7 +1177,7 @@ void LLOutfitGallery::uploadPhoto(LLUUID outfit_id) { return; } - (new LLFilePickerReplyThread(boost::bind(&LLOutfitGallery::uploadOutfitImage, this, _1, outfit_id), LLFilePicker::FFLOAD_IMAGE, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLOutfitGallery::uploadOutfitImage, this, _1, outfit_id), LLFilePicker::FFLOAD_IMAGE, false); } void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filenames, LLUUID outfit_id) diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp index 3322e8a3df..3a4fc613b7 100644 --- a/indra/newview/llpanelblockedlist.cpp +++ b/indra/newview/llpanelblockedlist.cpp @@ -232,7 +232,7 @@ void LLPanelBlockedList::onFilterEdit(const std::string& search_string) void LLPanelBlockedList::callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names) { if (names.empty() || ids.empty()) return; - LLMute mute(ids[0], names[0].getAccountName(), LLMute::AGENT); + LLMute mute(ids[0], names[0].getUserName(), LLMute::AGENT); LLMuteList::getInstance()->add(mute); showPanelAndSelect(mute.mID); } diff --git a/indra/newview/llpaneleditsky.cpp b/indra/newview/llpaneleditsky.cpp index a169712bd8..d17845ebc5 100644 --- a/indra/newview/llpaneleditsky.cpp +++ b/indra/newview/llpaneleditsky.cpp @@ -108,6 +108,8 @@ namespace const std::string FIELD_SKY_DENSITY_DROPLET_RADIUS("droplet_radius"); const std::string FIELD_SKY_DENSITY_ICE_LEVEL("ice_level"); + const std::string FIELD_REFLECTION_PROBE_AMBIANCE("probe_ambiance"); + const F32 SLIDER_SCALE_SUN_AMBIENT(3.0f); const F32 SLIDER_SCALE_BLUE_HORIZON_DENSITY(2.0f); const F32 SLIDER_SCALE_GLOW_R(20.0f); @@ -150,6 +152,7 @@ BOOL LLPanelSettingsSkyAtmosTab::postBuild() getChild<LLUICtrl>(FIELD_SKY_DENSITY_MOISTURE_LEVEL)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onMoistureLevelChanged(); }); getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onDropletRadiusChanged(); }); getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onIceLevelChanged(); }); + getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->setCommitCallback([this](LLUICtrl*, const LLSD&) { onReflectionProbeAmbianceChanged(); }); refresh(); return TRUE; @@ -172,6 +175,7 @@ void LLPanelSettingsSkyAtmosTab::setEnabled(BOOL enabled) getChild<LLUICtrl>(FIELD_SKY_DENSITY_MOISTURE_LEVEL)->setEnabled(enabled); getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->setEnabled(enabled); getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->setEnabled(enabled); + getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->setEnabled(enabled); } } @@ -203,10 +207,12 @@ void LLPanelSettingsSkyAtmosTab::refresh() F32 moisture_level = mSkySettings->getSkyMoistureLevel(); F32 droplet_radius = mSkySettings->getSkyDropletRadius(); F32 ice_level = mSkySettings->getSkyIceLevel(); + F32 rp_ambiance = mSkySettings->getReflectionProbeAmbiance(); getChild<LLUICtrl>(FIELD_SKY_DENSITY_MOISTURE_LEVEL)->setValue(moisture_level); getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->setValue(droplet_radius); getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->setValue(ice_level); + getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->setValue(rp_ambiance); } //------------------------------------------------------------------------- @@ -311,6 +317,15 @@ void LLPanelSettingsSkyAtmosTab::onIceLevelChanged() setIsDirty(); } +void LLPanelSettingsSkyAtmosTab::onReflectionProbeAmbianceChanged() +{ + if (!mSkySettings) return; + F32 ambiance = getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->getValue().asReal(); + mSkySettings->setReflectionProbeAmbiance(ambiance); + mSkySettings->update(); + setIsDirty(); +} + //========================================================================== LLPanelSettingsSkyCloudTab::LLPanelSettingsSkyCloudTab() : LLPanelSettingsSky() diff --git a/indra/newview/llpaneleditsky.h b/indra/newview/llpaneleditsky.h index cb63d40b0c..cd89e02eea 100644 --- a/indra/newview/llpaneleditsky.h +++ b/indra/newview/llpaneleditsky.h @@ -79,6 +79,7 @@ private: void onMoistureLevelChanged(); void onDropletRadiusChanged(); void onIceLevelChanged(); + void onReflectionProbeAmbianceChanged(); }; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index be11a4a9f3..6e897e2c7e 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1308,7 +1308,8 @@ void LLPanelEditWearable::changeCamera(U8 subpart) gMorphView->setCameraOffset( subpart_entry->mCameraOffset ); if (gSavedSettings.getBOOL("AppearanceCameraMovement")) { - gMorphView->updateCamera(); + gAgentCamera.setFocusOnAvatar(FALSE, FALSE); + gMorphView->updateCamera(); } } diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 71657239a6..ec67a9cdc6 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -38,6 +38,7 @@ #include "llfontgl.h" // project includes +#include "llagent.h" #include "llagentdata.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -45,9 +46,13 @@ #include "llcombobox.h" #include "lldrawpoolbump.h" #include "llface.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" // gInventory +#include "llinventorymodelbackgroundfetch.h" #include "lllineeditor.h" #include "llmaterialmgr.h" #include "llmediaentry.h" +#include "llmenubutton.h" #include "llnotificationsutil.h" #include "llradiogroup.h" #include "llresmgr.h" @@ -57,6 +62,8 @@ #include "lltexturectrl.h" #include "lltextureentry.h" #include "lltooldraganddrop.h" +#include "lltoolface.h" +#include "lltoolmgr.h" #include "lltrans.h" #include "llui.h" #include "llviewercontrol.h" @@ -69,6 +76,18 @@ #include "llpluginclassmedia.h" #include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI + + +#include "llagent.h" +#include "llfilesystem.h" +#include "llviewerassetupload.h" +#include "llviewermenufile.h" +#include "llsd.h" +#include "llsdutil.h" +#include "llsdserialize.h" +#include "llinventorymodel.h" + + // // Constant definitions for comboboxes // Must match the commbobox definitions in panel_tools_texture.xml @@ -123,6 +142,7 @@ F32 LLPanelFace::getCurrentShinyScaleU() { return getChild<LLUICtrl>("shinySca F32 LLPanelFace::getCurrentShinyScaleV() { return getChild<LLUICtrl>("shinyScaleV")->getValue().asReal(); } F32 LLPanelFace::getCurrentShinyOffsetU() { return getChild<LLUICtrl>("shinyOffsetU")->getValue().asReal(); } F32 LLPanelFace::getCurrentShinyOffsetV() { return getChild<LLUICtrl>("shinyOffsetV")->getValue().asReal(); } +LLUUID LLPanelFace::getCurrentMaterialID() { return getChild<LLUICtrl>("materialID")->getValue().asUUID(); } // // Methods @@ -154,9 +174,11 @@ BOOL LLPanelFace::postBuild() childSetCommitCallback("glossiness",&LLPanelFace::onCommitMaterialGloss, this); childSetCommitCallback("environment",&LLPanelFace::onCommitMaterialEnv, this); childSetCommitCallback("maskcutoff",&LLPanelFace::onCommitMaterialMaskCutoff, this); + childSetCommitCallback("materialID", &LLPanelFace::onCommitMaterialID, this); childSetAction("button align",&LLPanelFace::onClickAutoFix,this); childSetAction("button align textures", &LLPanelFace::onAlignTexture, this); + childSetAction("button save material", &LLPanelFace::onSaveMaterial, this); LLTextureCtrl* mTextureCtrl; LLTextureCtrl* mShinyTextureCtrl; @@ -298,7 +320,9 @@ BOOL LLPanelFace::postBuild() { mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this); } - + + mMenuClipboardColor = getChild<LLMenuButton>("clipboard_color_params_btn"); + mMenuClipboardTexture = getChild<LLMenuButton>("clipboard_texture_params_btn"); clearCtrls(); @@ -309,7 +333,9 @@ LLPanelFace::LLPanelFace() : LLPanel(), mIsAlpha(false) { - USE_TEXTURE = LLTrans::getString("use_texture"); + USE_TEXTURE = LLTrans::getString("use_texture"); + mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2)); + mEnableCallbackRegistrar.add("PanelFace.menuEnable", boost::bind(&LLPanelFace::menuEnableItem, this, _2)); } @@ -319,6 +345,13 @@ LLPanelFace::~LLPanelFace() } +void LLPanelFace::draw() +{ + updateCopyTexButton(); + + LLPanel::draw(); +} + void LLPanelFace::sendTexture() { LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("texture control"); @@ -1409,7 +1442,15 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) LLMaterialPtr material; LLSelectedTEMaterial::getCurrent(material, identical); - if (material && editable) + // enable this UI box if a single face is selected. + BOOL is_single_face = !LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected(); + childSetEnabled("button save material", static_cast<bool>(is_single_face)); + childSetEnabled("materialID", static_cast<bool>(is_single_face)); // doesn't work - why? + + // TODO: 2022-04 conflicts with media button placement. hide the button if applying media + // i.e. childSetVisible("button save material", !applying_media); + + if (material && editable) { LL_DEBUGS("Materials") << material->asLLSD() << LL_ENDL; @@ -1508,6 +1549,9 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } } + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + BOOL single_volume = (selected_count == 1); + mMenuClipboardColor->setEnabled(editable && single_volume); // Set variable values for numeric expressions LLCalc* calcp = LLCalc::getInstance(); @@ -1518,6 +1562,8 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) calcp->setVar(LLCalc::TEX_ROTATION, childGetValue("TexRot").asReal()); calcp->setVar(LLCalc::TEX_TRANSPARENCY, childGetValue("ColorTrans").asReal()); calcp->setVar(LLCalc::TEX_GLOW, childGetValue("glow").asReal()); + + getChildView("materialID")->setEnabled(editable); } else { @@ -1568,6 +1614,17 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } +void LLPanelFace::updateCopyTexButton() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + mMenuClipboardTexture->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify() + && !objectp->isPermanentEnforced() && !objectp->isInventoryPending() + && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1)); + std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options"); + mMenuClipboardTexture->setToolTip(tooltip); + +} + void LLPanelFace::refresh() { LL_DEBUGS("Materials") << LL_ENDL; @@ -2302,6 +2359,17 @@ void LLPanelFace::onCommitMaterialMaskCutoff(LLUICtrl* ctrl, void* userdata) LLSelectedTEMaterial::setAlphaMaskCutoff(self,self->getCurrentAlphaMaskCutoff()); } +//static +void LLPanelFace::onCommitMaterialID(LLUICtrl* ctrl, void* userdata) +{ + LLPanelFace* self = static_cast<LLPanelFace*>(userdata); + LLUUID matID = self->getCurrentMaterialID(); + LLSelectedTEMaterial::setMaterialID(self, matID); + + // Temporary demo hack - replace the TE entries with those from the Material's LLSD + applyMaterialUUID(matID, userdata); +} + // static void LLPanelFace::onCommitTextureInfo( LLUICtrl* ctrl, void* userdata ) { @@ -2538,6 +2606,810 @@ void LLPanelFace::onAlignTexture(void* userdata) self->alignTestureLayer(); } +enum EPasteMode +{ + PASTE_COLOR, + PASTE_TEXTURE +}; + +struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor +{ + LLPanelFacePasteTexFunctor(LLPanelFace* panel, EPasteMode mode) : + mPanelFace(panel), mMode(mode) {} + + virtual bool apply(LLViewerObject* objectp, S32 te) + { + switch (mMode) + { + case PASTE_COLOR: + mPanelFace->onPasteColor(objectp, te); + break; + case PASTE_TEXTURE: + mPanelFace->onPasteTexture(objectp, te); + break; + } + return true; + } +private: + LLPanelFace *mPanelFace; + EPasteMode mMode; +}; + +struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor +{ + LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {} + virtual bool apply(LLViewerObject* object) + { + object->sendTEUpdate(); + if (mUpdateMedia) + { + LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object); + if (vo && vo->hasMedia()) + { + vo->sendMediaDataUpdate(); + } + } + return true; + } +private: + bool mUpdateMedia; +}; + +struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor +{ + virtual bool apply(LLViewerObject* objectp, S32 te) + { + if (objectp && objectp->getTE(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + const LLMediaEntry *media_data = tep->getMediaData(); + if (media_data) + { + if (media_data->getCurrentURL().empty() && media_data->getAutoPlay()) + { + viewer_media_t media_impl = + LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID()); + if (media_impl) + { + media_impl->navigateHome(); + } + } + } + } + return true; + } +}; + +void LLPanelFace::onCopyColor() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + return; + } + + if (mClipboardParams.has("color")) + { + mClipboardParams["color"].clear(); + } + else + { + mClipboardParams["color"] = LLSD::emptyArray(); + } + + std::map<LLUUID, LLUUID> asset_item_map; + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + mClipboardParams["color_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + LLSD te_data; + + // asLLSD() includes media + te_data["te"] = tep->asLLSD(); // Note: includes a lot more than just color/alpha/glow + + mClipboardParams["color"].append(te_data); + } + } + } +} + +void LLPanelFace::onPasteColor() +{ + if (!mClipboardParams.has("color")) + { + return; + } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + // not supposed to happen + LL_WARNS() << "Failed to paste color due to missing or wrong selection" << LL_ENDL; + return; + } + + bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + LLSD &clipboard = mClipboardParams["color"]; // array + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + S32 compare_tes = num_tes; + + if (face_selection_mode) + { + compare_tes = 0; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + compare_tes++; + } + } + } + + // we can copy if single face was copied in edit face mode or if face count matches + if (!((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) + && compare_tes != clipboard.size()) + { + LLSD notif_args; + if (face_selection_mode) + { + static std::string reason = getString("paste_error_face_selection_mismatch"); + notif_args["REASON"] = reason; + } + else + { + static std::string reason = getString("paste_error_object_face_count_mismatch"); + notif_args["REASON"] = reason; + } + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR); + selected_objects->applyToTEs(&paste_func); + + LLPanelFaceUpdateFunctor sendfunc(false); + selected_objects->applyToObjects(&sendfunc); +} + +void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) +{ + LLSD te_data; + LLSD &clipboard = mClipboardParams["color"]; // array + if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) + { + te_data = *(clipboard.beginArray()); + } + else if (clipboard[te]) + { + te_data = clipboard[te]; + } + else + { + return; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + if (te_data.has("te")) + { + // Color / Alpha + if (te_data["te"].has("colors")) + { + LLColor4 color = tep->getColor(); + + LLColor4 clip_color; + clip_color.setValue(te_data["te"]["colors"]); + + // Color + color.mV[VRED] = clip_color.mV[VRED]; + color.mV[VGREEN] = clip_color.mV[VGREEN]; + color.mV[VBLUE] = clip_color.mV[VBLUE]; + + // Alpha + color.mV[VALPHA] = clip_color.mV[VALPHA]; + + objectp->setTEColor(te, color); + } + + // Color/fullbright + if (te_data["te"].has("fullbright")) + { + objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger()); + } + + // Glow + if (te_data["te"].has("glow")) + { + objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal()); + } + } + } +} + +void LLPanelFace::onCopyTexture() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + return; + } + + if (mClipboardParams.has("texture")) + { + mClipboardParams["texture"].clear(); + } + else + { + mClipboardParams["texture"] = LLSD::emptyArray(); + } + + std::map<LLUUID, LLUUID> asset_item_map; + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + mClipboardParams["texture_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + LLSD te_data; + + // asLLSD() includes media + te_data["te"] = tep->asLLSD(); + te_data["te"]["shiny"] = tep->getShiny(); + te_data["te"]["bumpmap"] = tep->getBumpmap(); + te_data["te"]["bumpshiny"] = tep->getBumpShiny(); + te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright(); + + if (te_data["te"].has("imageid")) + { + LLUUID item_id; + LLUUID id = te_data["te"]["imageid"].asUUID(); + bool from_library = get_is_predefined_texture(id); + bool full_perm = from_library; + + if (!full_perm + && objectp->permCopy() + && objectp->permTransfer() + && objectp->permModify()) + { + // If agent created this object and nothing is limiting permissions, mark as full perm + // If agent was granted permission to edit objects owned and created by somebody else, mark full perm + // This check is not perfect since we can't figure out whom textures belong to so this ended up restrictive + std::string creator_app_link; + LLUUID creator_id; + LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link); + full_perm = objectp->mOwnerID == creator_id; + } + + if (id.notNull() && !full_perm) + { + std::map<LLUUID, LLUUID>::iterator iter = asset_item_map.find(id); + if (iter != asset_item_map.end()) + { + item_id = iter->second; + } + else + { + // What this does is simply searches inventory for item with same asset id, + // as result it is Hightly unreliable, leaves little control to user, borderline hack + // but there are little options to preserve permissions - multiple inventory + // items might reference same asset and inventory search is expensive. + bool no_transfer = false; + if (objectp->getInventoryItemByAsset(id)) + { + no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm(); + } + item_id = get_copy_free_item_by_asset_id(id, no_transfer); + // record value to avoid repeating inventory search when possible + asset_item_map[id] = item_id; + } + } + + if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID())) + { + full_perm = true; + from_library = true; + } + + { + te_data["te"]["itemfullperm"] = full_perm; + te_data["te"]["fromlibrary"] = from_library; + + // If full permission object, texture is free to copy, + // but otherwise we need to check inventory and extract permissions + // + // Normally we care only about restrictions for current user and objects + // don't inherit any 'next owner' permissions from texture, so there is + // no need to record item id if full_perm==true + if (!full_perm && !from_library && item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp) + { + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + te_data["te"]["imageitemid"] = item_id; + te_data["te"]["itemfullperm"] = itemp->getIsFullPerm(); + if (!itemp->isFinished()) + { + // needed for dropTextureAllFaces + LLInventoryModelBackgroundFetch::instance().start(item_id, false); + } + } + } + } + } + } + + LLMaterialPtr material_ptr = tep->getMaterialParams(); + if (!material_ptr.isNull()) + { + LLSD mat_data; + + mat_data["NormMap"] = material_ptr->getNormalID(); + mat_data["SpecMap"] = material_ptr->getSpecularID(); + + mat_data["NormRepX"] = material_ptr->getNormalRepeatX(); + mat_data["NormRepY"] = material_ptr->getNormalRepeatY(); + mat_data["NormOffX"] = material_ptr->getNormalOffsetX(); + mat_data["NormOffY"] = material_ptr->getNormalOffsetY(); + mat_data["NormRot"] = material_ptr->getNormalRotation(); + + mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX(); + mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY(); + mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX(); + mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY(); + mat_data["SpecRot"] = material_ptr->getSpecularRotation(); + + mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue(); + mat_data["SpecExp"] = material_ptr->getSpecularLightExponent(); + mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity(); + mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff(); + mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode(); + + // Replace no-copy textures, destination texture will get used instead if available + if (mat_data.has("NormMap")) + { + LLUUID id = mat_data["NormMap"].asUUID(); + if (id.notNull() && !get_can_copy_texture(id)) + { + mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["NormMapNoCopy"] = true; + } + + } + if (mat_data.has("SpecMap")) + { + LLUUID id = mat_data["SpecMap"].asUUID(); + if (id.notNull() && !get_can_copy_texture(id)) + { + mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["SpecMapNoCopy"] = true; + } + + } + + te_data["material"] = mat_data; + } + + mClipboardParams["texture"].append(te_data); + } + } + } +} + +void LLPanelFace::onPasteTexture() +{ + if (!mClipboardParams.has("texture")) + { + return; + } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + // not supposed to happen + LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL; + return; + } + + bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + LLSD &clipboard = mClipboardParams["texture"]; // array + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + S32 compare_tes = num_tes; + + if (face_selection_mode) + { + compare_tes = 0; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + compare_tes++; + } + } + } + + // we can copy if single face was copied in edit face mode or if face count matches + if (!((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) + && compare_tes != clipboard.size()) + { + LLSD notif_args; + if (face_selection_mode) + { + static std::string reason = getString("paste_error_face_selection_mismatch"); + notif_args["REASON"] = reason; + } + else + { + static std::string reason = getString("paste_error_object_face_count_mismatch"); + notif_args["REASON"] = reason; + } + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + + bool full_perm_object = true; + LLSD::array_const_iterator iter = clipboard.beginArray(); + LLSD::array_const_iterator end = clipboard.endArray(); + for (; iter != end; ++iter) + { + const LLSD& te_data = *iter; + if (te_data.has("te") && te_data["te"].has("imageid")) + { + bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + full_perm_object &= full_perm; + if (!full_perm) + { + if (te_data["te"].has("imageitemid")) + { + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (!itemp) + { + // image might be in object's inventory, but it can be not up to date + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + } + } + else + { + // Item was not found on 'copy' stage + // Since this happened at copy, might be better to either show this + // at copy stage or to drop clipboard here + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + } + } + } + + if (!full_perm_object) + { + LLNotificationsUtil::add("FacePasteTexturePermissions"); + } + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); + selected_objects->applyToTEs(&paste_func); + + LLPanelFaceUpdateFunctor sendfunc(true); + selected_objects->applyToObjects(&sendfunc); + + LLPanelFaceNavigateHomeFunctor navigate_home_func; + selected_objects->applyToTEs(&navigate_home_func); +} + +void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) +{ + LLSD te_data; + LLSD &clipboard = mClipboardParams["texture"]; // array + if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) + { + te_data = *(clipboard.beginArray()); + } + else if (clipboard[te]) + { + te_data = clipboard[te]; + } + else + { + return; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + if (te_data.has("te")) + { + // Texture + bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean(); + if (te_data["te"].has("imageid")) + { + const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id + LLViewerInventoryItem* itemp_res = NULL; + + if (te_data["te"].has("imageitemid")) + { + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + itemp_res = itemp; + } + else + { + // Theoretically shouldn't happend, but if it does happen, we + // might need to add a notification to user that paste will fail + // since inventory isn't fully loaded + LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL; + } + } + } + // for case when item got removed from inventory after we pressed 'copy' + // or texture got pasted into previous object + if (!itemp_res && !full_perm) + { + // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable. + LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL; + // Todo: fix this, we are often searching same texture multiple times (equal to number of faces) + // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(imageid); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + // Extremely unreliable and perfomance unfriendly. + // But we need this to check permissions and it is how texture control finds items + for (S32 i = 0; i < items.size(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + itemp_res = itemp; + break; // first match + } + } + } + } + + if (itemp_res) + { + if (te == -1) // all faces + { + LLToolDragAndDrop::dropTextureAllFaces(objectp, + itemp_res, + from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null); + } + else // one face + { + LLToolDragAndDrop::dropTextureOneFace(objectp, + te, + itemp_res, + from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null, + 0); + } + } + // not an inventory item or no complete items + else if (full_perm) + { + // Either library, local or existed as fullperm when user made a copy + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + objectp->setTEImage(U8(te), image); + } + } + + if (te_data["te"].has("bumpmap")) + { + objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger()); + } + if (te_data["te"].has("bumpshiny")) + { + objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger()); + } + if (te_data["te"].has("bumpfullbright")) + { + objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger()); + } + + // Texture map + if (te_data["te"].has("scales") && te_data["te"].has("scalet")) + { + objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal()); + } + if (te_data["te"].has("offsets") && te_data["te"].has("offsett")) + { + objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal()); + } + if (te_data["te"].has("imagerot")) + { + objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal()); + } + + // Media + if (te_data["te"].has("media_flags")) + { + U8 media_flags = te_data["te"]["media_flags"].asInteger(); + objectp->setTEMediaFlags(te, media_flags); + LLVOVolume *vo = dynamic_cast<LLVOVolume*>(objectp); + if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY)) + { + vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/); + } + } + else + { + // Keep media flags on destination unchanged + } + } + + if (te_data.has("material")) + { + LLUUID object_id = objectp->getID(); + + LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); + + // Normal + // Replace placeholders with target's + if (te_data["material"].has("NormMapNoCopy")) + { + LLMaterialPtr material = tep->getMaterialParams(); + if (material.notNull()) + { + LLUUID id = material->getNormalID(); + if (id.notNull()) + { + te_data["material"]["NormMap"] = id; + } + } + } + LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id); + LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id); + + // Specular + // Replace placeholders with target's + if (te_data["material"].has("SpecMapNoCopy")) + { + LLMaterialPtr material = tep->getMaterialParams(); + if (material.notNull()) + { + LLUUID id = material->getSpecularID(); + if (id.notNull()) + { + te_data["material"]["SpecMap"] = id; + } + } + } + LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id); + LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id); + LLColor4 spec_color(te_data["material"]["SpecColor"]); + LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te); + LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); + LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); + LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); + if (te_data.has("te") && te_data["te"].has("shiny")) + { + objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger()); + } + } + } +} + +void LLPanelFace::menuDoToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste + if (command == "color_paste") + { + onPasteColor(); + } + else if (command == "texture_paste") + { + onPasteTexture(); + } + // copy + else if (command == "color_copy") + { + onCopyColor(); + } + else if (command == "texture_copy") + { + onCopyTexture(); + } +} + +bool LLPanelFace::menuEnableItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste options + if (command == "color_paste") + { + return mClipboardParams.has("color"); + } + else if (command == "texture_paste") + { + return mClipboardParams.has("texture"); + } + return false; +} + // TODO: I don't know who put these in or what these are for??? void LLPanelFace::setMediaURL(const std::string& url) @@ -2824,3 +3696,197 @@ void LLPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identic } max_diff_repeats_func; identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats ); } + + +void LLPanelFace::onSaveMaterial(void* userdata) +{ + // DRTVWR-559, Q&D material picker - save to inventory goes here + LL_DEBUGS("Material") << "saving render material to inventory" << LL_ENDL; + + std::string name = "New Material"; + + LLSD material_data = llsd::map( + "version", "1", + "material", LLSD::emptyMap() + ); + + // gen a new uuid for this asset + LLTransactionID tid; + tid.generate(); // timestamp-based randomization + uniquification + LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + + material_data["material"] = renderMaterialToLLSD(new_asset_id, userdata); + std::stringstream output; + LLSDSerialize::toNotation(material_data, output); + + //S32 expected_upload_cost = 0;// LLAgentBenefitsMgr::current().getTextureUploadCost(); + + std::string res_name = name; + std::string res_desc = "Saved Material"; + //LLFolderType::EType folder_type = LLFolderType::FT_MATERIAL; + //LLInventoryType::EType inv_type = LLInventoryType::IT_MATERIAL; + U32 next_owner_perm = LLPermissions::DEFAULT.getMaskNextOwner(); + + LLUUID parent = gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL); + const U8 subtype = NO_INV_SUBTYPE; // TODO maybe use AT_SETTINGS and LLSettingsType::ST_MATERIAL ? + + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), parent, tid, res_name, res_desc, + LLAssetType::AT_MATERIAL, LLInventoryType::IT_MATERIAL, subtype, next_owner_perm, + new LLBoostFuncInventoryCallback([output=output.str()](LLUUID const & inv_item_id){ + // from reference in LLSettingsVOBase::createInventoryItem()/updateInventoryItem() + LLResourceUploadInfo::ptr_t uploadInfo = + std::make_shared<LLBufferedAssetUploadInfo>( + inv_item_id, + LLAssetType::AT_SETTINGS, // TODO switch to AT_MATERIAL + output, + [](LLUUID item_id, LLUUID new_asset_id, LLUUID new_item_id, LLSD response) { + LL_INFOS("Material") << "inventory item uploaded. item: " << item_id << " asset: " << new_asset_id << " new_item_id: " << new_item_id << " response: " << response << LL_ENDL; + LLSD params = llsd::map("ASSET_ID", new_asset_id); + LLNotificationsUtil::add("MaterialCreated", params); + }); + + const LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string agent_url(region->getCapability("UpdateSettingsAgentInventory")); + if (agent_url.empty()) + { + LL_ERRS() << "missing required agent inventory cap url" << LL_ENDL; + } + LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo); + } + }) + ); + +} + +// Fill an LLSD with data describing the current face's texture settings +// TODO 2022-05 FUBAR there are both colliding and different data in LLPanelFace vs the TE. Also, neither one has the diffuse tex settings. +// +LLSD LLPanelFace::renderMaterialToLLSD(LLUUID uuid, void* userdata) +{ + llassert(userdata != nullptr); + + LLSD sd; + + sd.insert("RenderMaterialUUID", LLSD(uuid)); + + // now pull same data from the selected TE (same but different. W T F?) + LLMaterialPtr mat = nullptr; + bool ident; // ? + LLSelectedTEMaterial::getCurrent(mat, ident); + + if (mat) + { + sd.insert("teMaterialID", LLSD(mat->getMaterialID())); + + sd.insert("teNormalMap", LLSD(mat->getNormalID())); + sd.insert("teNormalOffsetX", LLSD(mat->getNormalOffsetX())); + sd.insert("teNormalOffsetY", LLSD(mat->getNormalOffsetY())); + sd.insert("teNormalRepeatX", LLSD(mat->getNormalRepeatX())); + sd.insert("teNormalRepeatY", LLSD(mat->getNormalRepeatY())); + sd.insert("teNormalRotation", LLSD(mat->getNormalRotation())); + + sd.insert("teSpecularMap", LLSD(mat->getSpecularID())); + LLColor4U color = mat->getSpecularLightColor(); + + sd.insert("teSpecularColorR", LLSD(static_cast<S32>(color.mV[0]))); + sd.insert("teSpecularColorG", LLSD(static_cast<S32>(color.mV[1]))); + sd.insert("teSpecularColorB", LLSD(static_cast<S32>(color.mV[2]))); + sd.insert("teSpecularColorA", LLSD(static_cast<S32>(color.mV[3]))); + sd.insert("teSpecularExponent", LLSD(static_cast<S32>(mat->getSpecularLightExponent()))); + sd.insert("teSpecularOffsetX", LLSD(mat->getSpecularOffsetX())); + sd.insert("teSpecularOffsetY", LLSD(mat->getSpecularOffsetY())); + sd.insert("teSpecularRepeatX", LLSD(mat->getSpecularRepeatX())); + sd.insert("teSpecularRepeatY", LLSD(mat->getSpecularRepeatY())); + sd.insert("teSpecularRotation", LLSD(mat->getSpecularRotation())); + + sd.insert("teAlphaMode", LLSD(static_cast<S32>(mat->getDiffuseAlphaMode()))); + sd.insert("teAlphaCutoff", LLSD(static_cast<S32>(mat->getAlphaMaskCutoff()))); + sd.insert("teEnvIntensity", LLSD(static_cast<S32>(mat->getEnvironmentIntensity()))); + sd.insert("teShaderMask", LLSD(static_cast<S32>(mat->getShaderMask()))); + } + else + { + // pull data from the LLPanelFace + LLPanelFace* instance = static_cast<LLPanelFace*>(userdata); + sd.insert("pfNormalMap", LLSD(instance->getCurrentNormalMap())); + sd.insert("pfSpecularMap", LLSD(instance->getCurrentSpecularMap())); + sd.insert("pfShininess", LLSD(static_cast<S32>(instance->getCurrentShininess()))); + sd.insert("pfBumpiness", LLSD(static_cast<S32>(instance->getCurrentBumpiness()))); + sd.insert("pfAlphaMode", LLSD(static_cast<S32>(instance->getCurrentDiffuseAlphaMode()))); + sd.insert("pfAlphaCutoff", LLSD(static_cast<S32>(instance->getCurrentAlphaMaskCutoff()))); + sd.insert("pfEnvIntensity", LLSD(static_cast<S32>(instance->getCurrentEnvIntensity()))); + sd.insert("pfGlossiness", LLSD(static_cast<S32>(instance->getCurrentGlossiness()))); + sd.insert("pfNormalRotation", LLSD(instance->getCurrentBumpyRot())); + sd.insert("pfNormalScaleU", LLSD(instance->getCurrentBumpyScaleU())); + sd.insert("pfNormalScaleV", LLSD(instance->getCurrentBumpyScaleV())); + sd.insert("pfNormalOffsetU", LLSD(instance->getCurrentBumpyOffsetU())); + sd.insert("pfNormalOffsetV", LLSD(instance->getCurrentBumpyOffsetV())); + sd.insert("pfSpecularRotation", LLSD(instance->getCurrentShinyRot())); + sd.insert("pfSpecularScaleU", LLSD(instance->getCurrentShinyScaleU())); + sd.insert("pfSpecularScaleV", LLSD(instance->getCurrentShinyScaleV())); + sd.insert("pfSpecularOffsetU", LLSD(instance->getCurrentShinyOffsetU())); + sd.insert("pfSpecularOffsetV", LLSD(instance->getCurrentShinyOffsetV())); + sd.insert("pfMaterialID", LLSD(instance->getCurrentMaterialID())); + } + + return sd; +} + +// Take the individual texture settings from the material and apply to current face & TE +void LLPanelFace::applyMaterialUUID(LLUUID uuid, void* userdata) +{ + llassert(userdata != nullptr); + //LLPanelFace* instance = static_cast<LLPanelFace*>(userdata); + + LLFileSystem material_file(uuid, LLAssetType::AT_MATERIAL, LLFileSystem::READ); + S32 bufsize = material_file.getSize(); + llassert(bufsize > 0); + std::vector<U8> buffer(bufsize); + material_file.read(&buffer[0], bufsize); + std::istringstream input(std::string(buffer.begin(), buffer.end())); // TODO - extend LLFileSystem to expose iostream interface + LLSD matSD; + + LLSDSerialize::fromNotation(matSD, input, bufsize); + + LL_INFOS() << "dump matSD: " << matSD << LL_ENDL; + + // strip off the versioning wrapper for now + matSD = matSD["material"]; + + // wrong, oops. llassert(uuid == matSD.get("RenderMaterialUUID").asUUID()); // if not, whoo boy + + LLMaterialPtr mat = nullptr; + bool ident; // ? + LLSelectedTEMaterial::getCurrent(mat, ident); + + mat->setMaterialID(matSD.get("teMaterialID").asUUID()); + + mat->setNormalID(matSD.get("teNormalMap").asUUID()); + mat->setNormalOffsetX(matSD.get("teNormalOffsetX").asReal()); + mat->setNormalOffsetY(matSD.get("teNormalOffsetY").asReal()); + mat->setNormalRepeatX(matSD.get("teNormalRepeatX").asReal()); + mat->setNormalRepeatY(matSD.get("teNormalRepeatY").asReal()); + mat->setNormalRotation(matSD.get("teNormalRotation").asReal()); + + mat->setSpecularID(matSD.get("teSpecularMap").asUUID()); + LLColor4U color; + color.mV[0] = static_cast<U8>(matSD.get("teSecularColorR").asInteger()); + color.mV[1] = static_cast<U8>(matSD.get("teSecularColorG").asInteger()); + color.mV[2] = static_cast<U8>(matSD.get("teSecularColorB").asInteger()); + color.mV[3] = static_cast<U8>(matSD.get("teSecularColorA").asInteger()); + mat->setSpecularLightColor(color); + mat->setSpecularLightExponent(static_cast<U8>(matSD.get("teSpecularExponent").asInteger())); + mat->setSpecularOffsetX(matSD.get("teSpecularOffsetX").asReal()); + mat->setSpecularOffsetY(matSD.get("teSpecularOffsetY").asReal()); + mat->setSpecularRepeatX(matSD.get("teSpecularRepeatX").asReal()); + mat->setSpecularRepeatY(matSD.get("teSpecularRepeatY").asReal()); + mat->setSpecularRotation(matSD.get("teSpecularRotation").asReal()); + + mat->setDiffuseAlphaMode(static_cast<U8>(matSD.get("teAlphaMode").asInteger())); + mat->setAlphaMaskCutoff(static_cast<U8>(matSD.get("teAlphaCutoff").asInteger())); + mat->setEnvironmentIntensity(static_cast<U8>(matSD.get("teEnvIntensity").asInteger())); + //mat->setShaderMask(static_cast<U32>(matSD.get(teShaderMask").asInteger()); +} + diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 2d57d89a44..08dc619402 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -47,6 +47,7 @@ class LLUICtrl; class LLViewerObject; class LLFloater; class LLMaterialID; +class LLMenuButton; // Represents an edit for use in replicating the op across one or more materials in the selection set. // @@ -96,6 +97,8 @@ public: LLPanelFace(); virtual ~LLPanelFace(); + void draw(); + void refresh(); void setMediaURL(const std::string& url); void setMediaType(const std::string& mime_type); @@ -128,6 +131,8 @@ protected: void sendMedia(); void alignTestureLayer(); + void updateCopyTexButton(); + // this function is to return TRUE if the drag should succeed. static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item); @@ -191,6 +196,7 @@ protected: static void onCommitMaterialGloss( LLUICtrl* ctrl, void* userdata); static void onCommitMaterialEnv( LLUICtrl* ctrl, void* userdata); static void onCommitMaterialMaskCutoff( LLUICtrl* ctrl, void* userdata); + static void onCommitMaterialID( LLUICtrl* ctrl, void* userdata); static void onCommitMaterialsMedia( LLUICtrl* ctrl, void* userdata); static void onCommitMaterialType( LLUICtrl* ctrl, void* userdata); @@ -205,6 +211,22 @@ protected: static void onClickAutoFix(void*); static void onAlignTexture(void*); + static void onSaveMaterial(void*); + static LLSD renderMaterialToLLSD(LLUUID uuid, void* userdata); + static void applyMaterialUUID(LLUUID uuid, void*); + +public: // needs to be accessible to selection manager + void onCopyColor(); // records all selected faces + void onPasteColor(); // to specific face + void onPasteColor(LLViewerObject* objectp, S32 te); // to specific face + void onCopyTexture(); + void onPasteTexture(); + void onPasteTexture(LLViewerObject* objectp, S32 te); + +protected: + void menuDoToSelected(const LLSD& userdata); + bool menuEnableItem(const LLSD& userdata); + static F32 valueGlow(LLViewerObject* object, S32 face); @@ -233,6 +255,7 @@ private: F32 getCurrentShinyScaleV(); F32 getCurrentShinyOffsetU(); F32 getCurrentShinyOffsetV(); + LLUUID getCurrentMaterialID(); // Update visibility of controls to match current UI mode // (e.g. materials vs media editing) @@ -400,7 +423,10 @@ private: * If agent selects texture which is not allowed to be applied for the currently selected object, * all controls of the floater texture picker which allow to apply the texture will be disabled. */ - void onTextureSelectionChanged(LLInventoryItem* itemp); + void onTextureSelectionChanged(LLInventoryItem* itemp); + + LLMenuButton* mMenuClipboardColor; + LLMenuButton* mMenuClipboardTexture; bool mIsAlpha; @@ -415,7 +441,9 @@ private: * up-arrow on a spinner, and avoids running afoul of its throttle. */ bool mUpdateInFlight; - bool mUpdatePending; + bool mUpdatePending; + + LLSD mClipboardParams; public: #if defined(DEF_GET_MAT_STATE) @@ -497,6 +525,7 @@ public: DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID); DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID); DEF_EDIT_MAT_STATE(LLColor4U, const LLColor4U&,setSpecularLightColor); + DEF_EDIT_MAT_STATE(LLUUID, const LLUUID&, setMaterialID); }; class LLSelectedTE diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 375daf60f8..04d3236bf1 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -97,6 +97,7 @@ BOOL LLPanelGroupGeneral::postBuild() mEditCharter->setCommitCallback(onCommitAny, this); mEditCharter->setFocusReceivedCallback(boost::bind(onFocusEdit, _1, this)); mEditCharter->setFocusChangedCallback(boost::bind(onFocusEdit, _1, this)); + mEditCharter->setContentTrusted(false); } // Options @@ -575,7 +576,8 @@ void LLPanelGroupGeneral::update(LLGroupChange gc) if (mEditCharter) { - mEditCharter->setText(gdatap->mCharter); + mEditCharter->setParseURLs(!mAllowEdit || !can_change_ident); + mEditCharter->setText(gdatap->mCharter); } resetDirty(); diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index ab32ea3956..82f880c9ee 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -156,6 +156,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, case DAD_CALLINGCARD: case DAD_MESH: case DAD_SETTINGS: + case DAD_MATERIAL: { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 381b80fb66..9df3a8e31a 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -92,44 +92,6 @@ LLPointer<LLCredential> load_user_credentials(std::string &user_key) } } -// keys are lower case to be case insensitive so they are not always -// identical to names which retain user input, like: -// "AwEsOmE Resident" -> "awesome_resident" -std::string get_user_key_from_name(const std::string &username) -{ - std::string key = username; - LLStringUtil::trim(key); - LLStringUtil::toLower(key); - if (!LLGridManager::getInstance()->isSystemGrid()) - { - size_t separator_index = username.find_first_of(" "); - if (separator_index == username.npos) - { - // CRED_IDENTIFIER_TYPE_ACCOUNT - return key; - } - } - // CRED_IDENTIFIER_TYPE_AGENT - size_t separator_index = username.find_first_of(" ._"); - std::string first = username.substr(0, separator_index); - std::string last; - if (separator_index != username.npos) - { - last = username.substr(separator_index + 1, username.npos); - LLStringUtil::trim(last); - } - else - { - // ...on Linden grids, single username users as considered to have - // last name "Resident" - // *TODO: Make login.cgi support "account_name" like above - last = "resident"; - } - - key = first + "_" + last; - return key; -} - class LLLoginLocationAutoHandler : public LLCommandHandler { public: @@ -361,11 +323,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, username_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); username_combo->setKeystrokeOnEsc(TRUE); - if (!mFirstLoginThisInstall) - { - LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); - remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this)); - } + + LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); + remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this)); + getChild<LLCheckBoxCtrl>("remember_password")->setCommitCallback(boost::bind(&LLPanelLogin::onRememberPasswordCheck, this)); } void LLPanelLogin::addFavoritesToStartLocation() @@ -438,10 +399,22 @@ void LLPanelLogin::addFavoritesToStartLocation() combo->addSeparator(); LL_DEBUGS() << "Loading favorites for " << iter->first << LL_ENDL; LLSD user_llsd = iter->second; + bool update_password_setting = true; for (LLSD::array_const_iterator iter1 = user_llsd.beginArray(); iter1 != user_llsd.endArray(); ++iter1) { - std::string label = (*iter1)["name"].asString(); + if ((*iter1).has("save_password")) + { + bool save_password = (*iter1)["save_password"].asBoolean(); + gSavedSettings.setBOOL("RememberPassword", save_password); + if (!save_password) + { + getChild<LLButton>("connect_btn")->setEnabled(false); + } + update_password_setting = false; + } + + std::string label = (*iter1)["name"].asString(); std::string value = (*iter1)["slurl"].asString(); if(label != "" && value != "") { @@ -453,6 +426,10 @@ void LLPanelLogin::addFavoritesToStartLocation() } } } + if (update_password_setting) + { + gSavedSettings.setBOOL("UpdateRememberPasswordSetting", TRUE); + } break; } if (combo->getValue().asString().empty()) @@ -565,21 +542,12 @@ void LLPanelLogin::populateFields(LLPointer<LLCredential> credential, bool remem LL_WARNS() << "Attempted fillFields with no login view shown" << LL_ENDL; return; } - if (sInstance->mFirstLoginThisInstall) - { - LLUICtrl* remember_check = sInstance->getChild<LLUICtrl>("remember_check"); - remember_check->setValue(remember_psswrd); - // no list to populate - setFields(credential); - } - else - { - sInstance->getChild<LLUICtrl>("remember_name")->setValue(remember_user); - LLUICtrl* remember_password = sInstance->getChild<LLUICtrl>("remember_password"); - remember_password->setValue(remember_user && remember_psswrd); - remember_password->setEnabled(remember_user); - sInstance->populateUserList(credential); - } + + sInstance->getChild<LLUICtrl>("remember_name")->setValue(remember_user); + LLUICtrl* remember_password = sInstance->getChild<LLUICtrl>("remember_password"); + remember_password->setValue(remember_user && remember_psswrd); + remember_password->setEnabled(remember_user); + sInstance->populateUserList(credential); } //static @@ -690,39 +658,6 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, LL_INFOS("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL; // determine if the username is a first/last form or not. size_t separator_index = username.find_first_of(' '); - if (separator_index == username.npos - && !LLGridManager::getInstance()->isSystemGrid()) - { - LL_INFOS("Credentials", "Authentication") << "account: " << username << LL_ENDL; - // single username, so this is a 'clear' identifier - identifier["type"] = CRED_IDENTIFIER_TYPE_ACCOUNT; - identifier["account_name"] = username; - - if (LLPanelLogin::sInstance->mPasswordModified) - { - // password is plaintext - authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; - authenticator["secret"] = password; - } - else - { - credential = load_user_credentials(username); - if (credential.notNull()) - { - authenticator = credential->getAuthenticator(); - if (authenticator.emptyMap()) - { - // Likely caused by user trying to log in to non-system grid - // with unsupported name format, just retry - LL_WARNS() << "Authenticator failed to load for: " << username << LL_ENDL; - // password is plaintext - authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; - authenticator["secret"] = password; - } - } - } - } - else { // Be lenient in terms of what separators we allow for two-word names // and allow legacy users to login with firstname.lastname @@ -773,16 +708,9 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, } } credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator); - if (!sInstance->mFirstLoginThisInstall) - { - remember_psswrd = sInstance->getChild<LLUICtrl>("remember_password")->getValue(); - remember_user = sInstance->getChild<LLUICtrl>("remember_name")->getValue(); - } - else - { - remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); - remember_user = remember_psswrd; // on panel_login_first "remember_check" is named as 'remember me' - } + + remember_psswrd = sInstance->getChild<LLUICtrl>("remember_password")->getValue(); + remember_user = sInstance->getChild<LLUICtrl>("remember_name")->getValue(); } @@ -1145,17 +1073,18 @@ void LLPanelLogin::onUserListCommit(void*) } // static -// At the moment only happens if !mFirstLoginThisInstall void LLPanelLogin::onRememberUserCheck(void*) { - if (sInstance && !sInstance->mFirstLoginThisInstall) + if (sInstance) { LLCheckBoxCtrl* remember_name(sInstance->getChild<LLCheckBoxCtrl>("remember_name")); LLCheckBoxCtrl* remember_psswrd(sInstance->getChild<LLCheckBoxCtrl>("remember_password")); LLComboBox* user_combo(sInstance->getChild<LLComboBox>("username_combo")); bool remember = remember_name->getValue().asBoolean(); - if (user_combo->getCurrentIndex() != -1 && !remember) + if (!sInstance->mFirstLoginThisInstall + && user_combo->getCurrentIndex() != -1 + && !remember) { remember = true; remember_name->setValue(true); @@ -1169,6 +1098,14 @@ void LLPanelLogin::onRememberUserCheck(void*) } } +void LLPanelLogin::onRememberPasswordCheck(void*) +{ + if (sInstance) + { + gSavedSettings.setBOOL("UpdateRememberPasswordSetting", TRUE); + } +} + // static void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index c5e6b41def..c6254f72cf 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -107,6 +107,7 @@ private: static void onUserNameTextEnty(void*); static void onUserListCommit(void*); static void onRememberUserCheck(void*); + static void onRememberPasswordCheck(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void updateServerCombo(); diff --git a/indra/newview/llpanelloginlistener.cpp b/indra/newview/llpanelloginlistener.cpp index 33efde11f3..fb3e8dc244 100644 --- a/indra/newview/llpanelloginlistener.cpp +++ b/indra/newview/llpanelloginlistener.cpp @@ -47,5 +47,5 @@ LLPanelLoginListener::LLPanelLoginListener(LLPanelLogin* instance): void LLPanelLoginListener::onClickConnect(const LLSD&) const { - mPanel->onClickConnect(NULL); + mPanel->onClickConnect(false); } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 89256b40c4..49562da3f7 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -919,6 +919,7 @@ void LLFloaterInventoryFinder::updateElementsFromFilter() getChild<LLUICtrl>("check_clothing")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); getChild<LLUICtrl>("check_gesture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); getChild<LLUICtrl>("check_landmark")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); + getChild<LLUICtrl>("check_material")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_MATERIAL)); getChild<LLUICtrl>("check_notecard")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); getChild<LLUICtrl>("check_object")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); getChild<LLUICtrl>("check_script")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); @@ -975,6 +976,12 @@ void LLFloaterInventoryFinder::draw() filtered_by_all_types = FALSE; } + if (!getChild<LLUICtrl>("check_material")->getValue()) + { + filter &= ~(0x1 << LLInventoryType::IT_MATERIAL); + filtered_by_all_types = FALSE; + } + if (!getChild<LLUICtrl>("check_notecard")->getValue()) { filter &= ~(0x1 << LLInventoryType::IT_NOTECARD); @@ -1129,6 +1136,7 @@ void LLFloaterInventoryFinder::selectAllTypes(void* user_data) self->getChild<LLUICtrl>("check_clothing")->setValue(TRUE); self->getChild<LLUICtrl>("check_gesture")->setValue(TRUE); self->getChild<LLUICtrl>("check_landmark")->setValue(TRUE); + self->getChild<LLUICtrl>("check_material")->setValue(TRUE); self->getChild<LLUICtrl>("check_notecard")->setValue(TRUE); self->getChild<LLUICtrl>("check_object")->setValue(TRUE); self->getChild<LLUICtrl>("check_script")->setValue(TRUE); @@ -1149,6 +1157,7 @@ void LLFloaterInventoryFinder::selectNoTypes(void* user_data) self->getChild<LLUICtrl>("check_clothing")->setValue(FALSE); self->getChild<LLUICtrl>("check_gesture")->setValue(FALSE); self->getChild<LLUICtrl>("check_landmark")->setValue(FALSE); + self->getChild<LLUICtrl>("check_material")->setValue(FALSE); self->getChild<LLUICtrl>("check_notecard")->setValue(FALSE); self->getChild<LLUICtrl>("check_object")->setValue(FALSE); self->getChild<LLUICtrl>("check_script")->setValue(FALSE); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 831c89b005..0bfc1297d3 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -46,6 +46,7 @@ #include "llcombobox.h" #include "llfocusmgr.h" #include "llmanipscale.h" +#include "llmenubutton.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -117,8 +118,9 @@ BOOL LLPanelObject::postBuild() // Phantom checkbox mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl"); childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); - + // Position + mMenuClipboardPos = getChild<LLMenuButton>("clipboard_pos_btn"); mLabelPosition = getChild<LLTextBox>("label position"); mCtrlPosX = getChild<LLSpinCtrl>("Pos X"); childSetCommitCallback("Pos X",onCommitPosition,this); @@ -128,6 +130,7 @@ BOOL LLPanelObject::postBuild() childSetCommitCallback("Pos Z",onCommitPosition,this); // Scale + mMenuClipboardSize = getChild<LLMenuButton>("clipboard_size_btn"); mLabelSize = getChild<LLTextBox>("label size"); mCtrlScaleX = getChild<LLSpinCtrl>("Scale X"); childSetCommitCallback("Scale X",onCommitScale,this); @@ -141,6 +144,7 @@ BOOL LLPanelObject::postBuild() childSetCommitCallback("Scale Z",onCommitScale,this); // Rotation + mMenuClipboardRot = getChild<LLMenuButton>("clipboard_rot_btn"); mLabelRotation = getChild<LLTextBox>("label rotation"); mCtrlRotX = getChild<LLSpinCtrl>("Rot X"); childSetCommitCallback("Rot X",onCommitRotation,this); @@ -155,6 +159,8 @@ BOOL LLPanelObject::postBuild() mComboBaseType = getChild<LLComboBox>("comboBaseType"); childSetCommitCallback("comboBaseType",onCommitParametric,this); + mMenuClipboardParams = getChild<LLMenuButton>("clipboard_obj_params_btn"); + // Cut mLabelCut = getChild<LLTextBox>("text cut"); mSpinCutBegin = getChild<LLSpinCtrl>("cut begin"); @@ -285,8 +291,13 @@ LLPanelObject::LLPanelObject() mSelectedType(MI_BOX), mSculptTextureRevert(LLUUID::null), mSculptTypeRevert(0), + mHasClipboardPos(false), + mHasClipboardSize(false), + mHasClipboardRot(false), mSizeChanged(FALSE) { + mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2)); + mEnableCallbackRegistrar.add("PanelObject.menuEnable", boost::bind(&LLPanelObject::menuEnableItem, this, _2)); } @@ -373,7 +384,7 @@ void LLPanelObject::getState( ) calcp->clearVar(LLCalc::Z_POS); } - + mMenuClipboardPos->setEnabled(enable_move); mLabelPosition->setEnabled( enable_move ); mCtrlPosX->setEnabled(enable_move); mCtrlPosY->setEnabled(enable_move); @@ -399,6 +410,7 @@ void LLPanelObject::getState( ) calcp->setVar(LLCalc::Z_SCALE, 0.f); } + mMenuClipboardSize->setEnabled(enable_scale); mLabelSize->setEnabled( enable_scale ); mCtrlScaleX->setEnabled( enable_scale ); mCtrlScaleY->setEnabled( enable_scale ); @@ -430,6 +442,7 @@ void LLPanelObject::getState( ) calcp->clearVar(LLCalc::Z_ROT); } + mMenuClipboardRot->setEnabled(enable_rotate); mLabelRotation->setEnabled( enable_rotate ); mCtrlRotX->setEnabled( enable_rotate ); mCtrlRotY->setEnabled( enable_rotate ); @@ -607,7 +620,7 @@ void LLPanelObject::getState( ) } else { - LL_INFOS() << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL; + LL_INFOS("FloaterTools") << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL; selected_item = MI_BOX; } @@ -933,6 +946,7 @@ void LLPanelObject::getState( ) // Update field enablement mComboBaseType ->setEnabled( enabled ); + mMenuClipboardParams->setEnabled(enabled); mLabelCut ->setEnabled( enabled ); mSpinCutBegin ->setEnabled( enabled ); @@ -1093,7 +1107,8 @@ void LLPanelObject::getState( ) } mComboBaseType->setEnabled(!isMesh); - + mMenuClipboardParams->setEnabled(!isMesh); + if (mCtrlSculptType) { if (sculpt_stitching == LL_SCULPT_TYPE_NONE) @@ -1157,11 +1172,11 @@ void LLPanelObject::sendIsPhysical() LLSelectMgr::getInstance()->selectionUpdatePhysics(value); mIsPhysical = value; - LL_INFOS() << "update physics sent" << LL_ENDL; + LL_INFOS("FloaterTools") << "update physics sent" << LL_ENDL; } else { - LL_INFOS() << "update physics not changed" << LL_ENDL; + LL_INFOS("FloaterTools") << "update physics not changed" << LL_ENDL; } } @@ -1173,11 +1188,11 @@ void LLPanelObject::sendIsTemporary() LLSelectMgr::getInstance()->selectionUpdateTemporary(value); mIsTemporary = value; - LL_INFOS() << "update temporary sent" << LL_ENDL; + LL_INFOS("FloaterTools") << "update temporary sent" << LL_ENDL; } else { - LL_INFOS() << "update temporary not changed" << LL_ENDL; + LL_INFOS("FloaterTools") << "update temporary not changed" << LL_ENDL; } } @@ -1190,11 +1205,11 @@ void LLPanelObject::sendIsPhantom() LLSelectMgr::getInstance()->selectionUpdatePhantom(value); mIsPhantom = value; - LL_INFOS() << "update phantom sent" << LL_ENDL; + LL_INFOS("FloaterTools") << "update phantom sent" << LL_ENDL; } else { - LL_INFOS() << "update phantom not changed" << LL_ENDL; + LL_INFOS("FloaterTools") << "update phantom not changed" << LL_ENDL; } } @@ -1304,7 +1319,7 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params) break; default: - LL_WARNS() << "Unknown base type " << selected_type + LL_WARNS("FloaterTools") << "Unknown base type " << selected_type << " in getVolumeParams()" << LL_ENDL; // assume a box selected_type = MI_BOX; @@ -1644,13 +1659,15 @@ void LLPanelObject::sendPosition(BOOL btn_down) LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); LLViewerRegion* regionp = mObject->getRegion(); - // Clamp the Z height - const F32 height = newpos.mV[VZ]; - const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal()); - const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight(); + if (!regionp) return; if (!mObject->isAttachment()) { + // Clamp the Z height + const F32 height = newpos.mV[VZ]; + const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal()); + const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight(); + if ( height < min_height) { newpos.mV[VZ] = min_height; @@ -1672,8 +1689,19 @@ void LLPanelObject::sendPosition(BOOL btn_down) // Make sure new position is in a valid region, so the object // won't get dumped by the simulator. LLVector3d new_pos_global = regionp->getPosGlobalFromRegion(newpos); - - if ( LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global) ) + bool is_valid_pos = true; + if (mObject->isAttachment()) + { + LLVector3 delta_pos = mObject->getPositionEdit() - newpos; + LLVector3d attachment_pos = regionp->getPosGlobalFromRegion(mObject->getPositionRegion() + delta_pos); + is_valid_pos = LLWorld::getInstance()->positionRegionValidGlobal(attachment_pos); + } + else + { + is_valid_pos = LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global); + } + + if (is_valid_pos) { // send only if the position is changed, that is, the delta vector is not zero LLVector3d old_pos_global = mObject->getPositionGlobal(); @@ -2000,3 +2028,283 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata) self->sendSculpt(); } + +void LLPanelObject::menuDoToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste + if (command == "psr_paste") + { + onPastePos(); + onPasteSize(); + onPasteRot(); + } + else if (command == "pos_paste") + { + onPastePos(); + } + else if (command == "size_paste") + { + onPasteSize(); + } + else if (command == "rot_paste") + { + onPasteRot(); + } + else if (command == "params_paste") + { + onPasteParams(); + } + // copy + else if (command == "psr_copy") + { + onCopyPos(); + onCopySize(); + onCopyRot(); + } + else if (command == "pos_copy") + { + onCopyPos(); + } + else if (command == "size_copy") + { + onCopySize(); + } + else if (command == "rot_copy") + { + onCopyRot(); + } + else if (command == "params_copy") + { + onCopyParams(); + } +} + +bool LLPanelObject::menuEnableItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste options + if (command == "psr_paste") + { + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME)) + && (selected_count == 1); + + if (!single_volume) + { + return false; + } + + bool enable_move; + bool enable_modify; + + LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify); + + return enable_move && enable_modify && mHasClipboardPos && mHasClipboardSize && mHasClipboardRot; + } + else if (command == "pos_paste") + { + // assumes that menu won't be active if there is no move permission + return mHasClipboardPos; + } + else if (command == "size_paste") + { + return mHasClipboardSize; + } + else if (command == "rot_paste") + { + return mHasClipboardRot; + } + else if (command == "params_paste") + { + return mClipboardParams.isMap() && !mClipboardParams.emptyMap(); + } + // copy options + else if (command == "psr_copy") + { + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME)) + && (selected_count == 1); + + if (!single_volume) + { + return false; + } + + bool enable_move; + bool enable_modify; + + LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify); + + // since we forbid seeing values we also should forbid copying them + return enable_move && enable_modify; + } + return false; +} + +void LLPanelObject::onCopyPos() +{ + mClipboardPos = LLVector3(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); + + std::string stringVec = llformat("<%g, %g, %g>", mClipboardPos.mV[VX], mClipboardPos.mV[VY], mClipboardPos.mV[VZ]); + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); + + mHasClipboardPos = true; +} + +void LLPanelObject::onCopySize() +{ + mClipboardSize = LLVector3(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); + + std::string stringVec = llformat("<%g, %g, %g>", mClipboardSize.mV[VX], mClipboardSize.mV[VY], mClipboardSize.mV[VZ]); + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); + + mHasClipboardSize = true; +} + +void LLPanelObject::onCopyRot() +{ + mClipboardRot = LLVector3(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); + + std::string stringVec = llformat("<%g, %g, %g>", mClipboardRot.mV[VX], mClipboardRot.mV[VY], mClipboardRot.mV[VZ]); + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); + + mHasClipboardRot = true; +} + +void LLPanelObject::onPastePos() +{ + if (!mHasClipboardPos) return; + if (mObject.isNull()) return; + + LLViewerRegion* regionp = mObject->getRegion(); + if (!regionp) return; + + + // Clamp pos on non-attachments, just keep the prims within the region + if (!mObject->isAttachment()) + { + F32 max_width = regionp->getWidth(); // meters + mClipboardPos.mV[VX] = llclamp(mClipboardPos.mV[VX], 0.f, max_width); + mClipboardPos.mV[VY] = llclamp(mClipboardPos.mV[VY], 0.f, max_width); + //height will get properly clamped by sendPosition + } + + mCtrlPosX->set( mClipboardPos.mV[VX] ); + mCtrlPosY->set( mClipboardPos.mV[VY] ); + mCtrlPosZ->set( mClipboardPos.mV[VZ] ); + + sendPosition(FALSE); +} + +void LLPanelObject::onPasteSize() +{ + if (!mHasClipboardSize) return; + + mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); + mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); + mClipboardSize.mV[VZ] = llclamp(mClipboardSize.mV[VZ], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); + + mCtrlScaleX->set(mClipboardSize.mV[VX]); + mCtrlScaleY->set(mClipboardSize.mV[VY]); + mCtrlScaleZ->set(mClipboardSize.mV[VZ]); + + sendScale(FALSE); +} + +void LLPanelObject::onPasteRot() +{ + if (!mHasClipboardRot) return; + + mCtrlRotX->set(mClipboardRot.mV[VX]); + mCtrlRotY->set(mClipboardRot.mV[VY]); + mCtrlRotZ->set(mClipboardRot.mV[VZ]); + + sendRotation(FALSE); +} + +void LLPanelObject::onCopyParams() +{ + LLViewerObject* objectp = mObject; + if (!objectp || objectp->isMesh()) + { + return; + } + + mClipboardParams.clear(); + + // Parametrics + LLVolumeParams params; + getVolumeParams(params); + mClipboardParams["volume_params"] = params.asLLSD(); + + // Sculpted Prim + if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + { + LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + + LLUUID texture_id = sculpt_params->getSculptTexture(); + if (get_can_copy_texture(texture_id)) + { + LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL; + mClipboardParams["sculpt"]["id"] = texture_id; + } + else + { + mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); + } + + mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType(); + } +} + +void LLPanelObject::onPasteParams() +{ + LLViewerObject* objectp = mObject; + if (!objectp) + { + return; + } + + // Sculpted Prim + if (mClipboardParams.has("sculpt")) + { + LLSculptParams sculpt_params; + LLUUID sculpt_id = mClipboardParams["sculpt"]["id"].asUUID(); + U8 sculpt_type = (U8)mClipboardParams["sculpt"]["type"].asInteger(); + sculpt_params.setSculptTexture(sculpt_id, sculpt_type); + objectp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); + } + else + { + LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if (sculpt_params) + { + objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); + } + } + + // volume params + // make sure updateVolume() won't affect flexible + if (mClipboardParams.has("volume_params")) + { + LLVolumeParams params; + params.fromLLSD(mClipboardParams["volume_params"]); + LLVOVolume *volobjp = (LLVOVolume *)objectp; + if (volobjp->isFlexible()) + { + if (params.getPathParams().getCurveType() == LL_PCODE_PATH_LINE) + { + params.getPathParams().setCurveType(LL_PCODE_PATH_FLEXIBLE); + } + } + else if (params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) + { + params.getPathParams().setCurveType(LL_PCODE_PATH_LINE); + } + + objectp->updateVolume(params); + } +} diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 8829f493fa..515dd27c0a 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -37,6 +37,7 @@ class LLCheckBoxCtrl; class LLTextBox; class LLUICtrl; class LLButton; +class LLMenuButton; class LLViewerObject; class LLComboBox; class LLColorSwatchCtrl; @@ -66,6 +67,14 @@ public: static void onCommitPhantom( LLUICtrl* ctrl, void* userdata); static void onCommitPhysics( LLUICtrl* ctrl, void* userdata); + void onCopyPos(); + void onPastePos(); + void onCopySize(); + void onPasteSize(); + void onCopyRot(); + void onPasteRot(); + void onCopyParams(); + void onPasteParams(); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -75,6 +84,9 @@ public: BOOL onDropSculpt(LLInventoryItem* item); static void onCommitSculptType( LLUICtrl *ctrl, void* userdata); + void menuDoToSelected(const LLSD& userdata); + bool menuEnableItem(const LLSD& userdata); + protected: void getState(); @@ -92,6 +104,7 @@ protected: protected: // Per-object options LLComboBox* mComboBaseType; + LLMenuButton* mMenuClipboardParams; LLTextBox* mLabelCut; LLSpinCtrl* mSpinCutBegin; @@ -131,17 +144,20 @@ protected: LLTextBox* mLabelRevolutions; LLSpinCtrl* mSpinRevolutions; + LLMenuButton* mMenuClipboardPos; LLTextBox* mLabelPosition; LLSpinCtrl* mCtrlPosX; LLSpinCtrl* mCtrlPosY; LLSpinCtrl* mCtrlPosZ; + LLMenuButton* mMenuClipboardSize; LLTextBox* mLabelSize; LLSpinCtrl* mCtrlScaleX; LLSpinCtrl* mCtrlScaleY; LLSpinCtrl* mCtrlScaleZ; BOOL mSizeChanged; + LLMenuButton* mMenuClipboardRot; LLTextBox* mLabelRotation; LLSpinCtrl* mCtrlRotX; LLSpinCtrl* mCtrlRotY; @@ -157,7 +173,7 @@ protected: LLComboBox *mCtrlSculptType; LLCheckBoxCtrl *mCtrlSculptMirror; LLCheckBoxCtrl *mCtrlSculptInvert; - + LLVector3 mCurEulerDegrees; // to avoid sending rotation when not changed BOOL mIsPhysical; // to avoid sending "physical" when not changed BOOL mIsTemporary; // to avoid sending "temporary" when not changed @@ -167,6 +183,15 @@ protected: LLUUID mSculptTextureRevert; // so we can revert the sculpt texture on cancel U8 mSculptTypeRevert; // so we can revert the sculpt type on cancel + LLVector3 mClipboardPos; + LLVector3 mClipboardSize; + LLVector3 mClipboardRot; + LLSD mClipboardParams; + + bool mHasClipboardPos; + bool mHasClipboardSize; + bool mHasClipboardRot; + LLPointer<LLViewerObject> mObject; LLPointer<LLViewerObject> mRootObject; }; diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 0d987df6ca..2faa3a7137 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -618,7 +618,18 @@ const std::string& LLTaskCategoryBridge::getDisplayName() const if (cat) { - mDisplayName.assign(cat->getName()); + std::string name = cat->getName(); + if (mChildren.size() > 0) + { + // Add item count + // Normally we would be using getLabelSuffix for this + // but object's inventory just uses displaynames + LLStringUtil::format_map_t args; + args["[ITEMS_COUNT]"] = llformat("%d", mChildren.size()); + + name.append(" " + LLTrans::getString("InventoryItemsCount", args)); + } + mDisplayName.assign(name); } return mDisplayName; @@ -704,6 +715,7 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_CALLINGCARD: case DAD_MESH: case DAD_SETTINGS: + case DAD_MATERIAL: accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); if(accept && drop) { @@ -1151,6 +1163,56 @@ LLSettingsType::type_e LLTaskSettingsBridge::getSettingsType() const } ///---------------------------------------------------------------------------- +/// Class LLTaskMaterialBridge +///---------------------------------------------------------------------------- + +class LLTaskMaterialBridge : public LLTaskInvFVBridge +{ +public: + LLTaskMaterialBridge(LLPanelObjectInventory* panel, + const LLUUID& uuid, + const std::string& name) : + LLTaskInvFVBridge(panel, uuid, name) {} + + BOOL canOpenItem() const override { return TRUE; } + void openItem() override; + BOOL removeItem() override; +}; + +void LLTaskMaterialBridge::openItem() +{ + LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); + if(!object || object->isInventoryPending()) + { + return; + } + + // Note: even if we are not allowed to modify copyable notecard, we should be able to view it + LLInventoryItem *item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mUUID)); + BOOL item_copy = item && gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE); + if( item_copy + || object->permModify() + || gAgent.isGodlike()) + { + LLSD floater_key; + floater_key["taskid"] = mPanel->getTaskUUID(); + floater_key["itemid"] = mUUID; + LLPreviewNotecard* preview = LLFloaterReg::showTypedInstance<LLPreviewNotecard>("preview_notecard", floater_key, TAKE_FOCUS_YES); + if (preview) + { + preview->setObjectID(mPanel->getTaskUUID()); + } + } +} + +BOOL LLTaskMaterialBridge::removeItem() +{ + LLFloaterReg::hideInstance("preview_notecard", LLSD(mUUID)); + return LLTaskInvFVBridge::removeItem(); +} + + +///---------------------------------------------------------------------------- /// LLTaskInvFVBridge impl //---------------------------------------------------------------------------- @@ -1237,6 +1299,11 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* object_name, itemflags); break; + case LLAssetType::AT_MATERIAL: + new_bridge = new LLTaskMaterialBridge(panel, + object_id, + object_name); + break; default: LL_INFOS() << "Unhandled inventory type (llassetstorage.h): " << (S32)type << LL_ENDL; @@ -1522,6 +1589,8 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root { createViewsForCategory(&contents, inventory_root, new_folder); } + // Refresh for label to add item count + new_folder->refresh(); } } diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 89c558e4f8..5c93271446 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -51,6 +51,7 @@ #include "llfocusmgr.h" #include "llmanipscale.h" #include "llinventorymodel.h" +#include "llmenubutton.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -145,6 +146,15 @@ BOOL LLPanelVolume::postBuild() getChild<LLUICtrl>("Light Ambiance")->setValidateBeforeCommit( precommitValidate); } + // REFLECTION PROBE Parameters + { + childSetCommitCallback("Reflection Probe", onCommitIsReflectionProbe, this); + childSetCommitCallback("Probe Dynamic", onCommitProbe, this); + childSetCommitCallback("Probe Volume Type", onCommitProbe, this); + childSetCommitCallback("Probe Ambiance", onCommitProbe, this); + childSetCommitCallback("Probe Near Clip", onCommitProbe, this); + } + // PHYSICS Parameters { // PhysicsShapeType combobox @@ -168,6 +178,9 @@ BOOL LLPanelVolume::postBuild() mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution)); } + mMenuClipboardFeatures = getChild<LLMenuButton>("clipboard_features_params_btn"); + mMenuClipboardLight = getChild<LLMenuButton>("clipboard_light_params_btn"); + std::map<std::string, std::string> material_name_map; material_name_map["Stone"]= LLTrans::getString("Stone"); material_name_map["Metal"]= LLTrans::getString("Metal"); @@ -208,6 +221,8 @@ LLPanelVolume::LLPanelVolume() { setMouseOpaque(FALSE); + mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", boost::bind(&LLPanelVolume::menuDoToSelected, this, _2)); + mEnableCallbackRegistrar.add("PanelVolume.menuEnable", boost::bind(&LLPanelVolume::menuEnableItem, this, _2)); } @@ -360,6 +375,43 @@ void LLPanelVolume::getState( ) getChildView("Light Ambiance")->setEnabled(false); } + // Reflection Probe + BOOL is_probe = volobjp && volobjp->isReflectionProbe(); + getChild<LLUICtrl>("Reflection Probe")->setValue(is_probe); + getChildView("Reflection Probe")->setEnabled(editable && single_volume && volobjp); + + bool probe_enabled = is_probe && editable && single_volume; + + getChildView("Probe Dynamic")->setEnabled(probe_enabled); + getChildView("Probe Volume Type")->setEnabled(probe_enabled); + getChildView("Probe Ambiance")->setEnabled(probe_enabled); + getChildView("Probe Near Clip")->setEnabled(probe_enabled); + + if (!probe_enabled) + { + getChild<LLComboBox>("Probe Volume Type", true)->clear(); + getChild<LLSpinCtrl>("Probe Ambiance", true)->clear(); + getChild<LLSpinCtrl>("Probe Near Clip", true)->clear(); + getChild<LLCheckBoxCtrl>("Probe Dynamic", true)->clear(); + } + else + { + std::string volume_type; + if (volobjp->getReflectionProbeIsBox()) + { + volume_type = "Box"; + } + else + { + volume_type = "Sphere"; + } + + getChild<LLComboBox>("Probe Volume Type", true)->setValue(volume_type); + getChild<LLSpinCtrl>("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance()); + getChild<LLSpinCtrl>("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip()); + getChild<LLCheckBoxCtrl>("Probe Dynamic", true)->setValue(volobjp->getReflectionProbeIsDynamic()); + } + // Animated Mesh BOOL is_animated_mesh = single_root_volume && root_volobjp && root_volobjp->isAnimatedObject(); getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh); @@ -409,7 +461,6 @@ void LLPanelVolume::getState( ) gAgentAvatarp->updateMeshVisibility(); } } - // Flexible properties BOOL is_flexible = volobjp && volobjp->isFlexible(); @@ -564,6 +615,9 @@ void LLPanelVolume::getState( ) mObject = objectp; mRootObject = root_objectp; + + mMenuClipboardFeatures->setEnabled(editable && single_volume && volobjp); // Note: physics doesn't need to be limited by single volume + mMenuClipboardLight->setEnabled(editable && single_volume && volobjp); } // static @@ -647,6 +701,11 @@ void LLPanelVolume::clearCtrls() getChildView("Light Radius")->setEnabled(false); getChildView("Light Falloff")->setEnabled(false); + getChildView("Reflection Probe")->setEnabled(false);; + getChildView("Probe Volume Type")->setEnabled(false); + getChildView("Probe Dynamic")->setEnabled(false); + getChildView("Probe Ambiance")->setEnabled(false); + getChildView("Probe Near Clip")->setEnabled(false); getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false); getChildView("Flexible1D Checkbox Ctrl")->setEnabled(false); getChildView("FlexNumSections")->setEnabled(false); @@ -684,6 +743,20 @@ void LLPanelVolume::sendIsLight() LL_INFOS() << "update light sent" << LL_ENDL; } +void LLPanelVolume::sendIsReflectionProbe() +{ + LLViewerObject* objectp = mObject; + if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME)) + { + return; + } + LLVOVolume* volobjp = (LLVOVolume*)objectp; + + BOOL value = getChild<LLUICtrl>("Reflection Probe")->getValue(); + volobjp->setIsReflectionProbe(value); + LL_INFOS() << "update reflection probe sent" << LL_ENDL; +} + void LLPanelVolume::sendIsFlexible() { LLViewerObject* objectp = mObject; @@ -831,6 +904,290 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) } } +void LLPanelVolume::onCopyFeatures() +{ + LLViewerObject* objectp = mObject; + if (!objectp) + { + return; + } + + LLSD clipboard; + + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + // Flexi Prim + if (volobjp && volobjp->isFlexible()) + { + LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + if (attributes) + { + clipboard["flex"]["lod"] = attributes->getSimulateLOD(); + clipboard["flex"]["gav"] = attributes->getGravity(); + clipboard["flex"]["ten"] = attributes->getTension(); + clipboard["flex"]["fri"] = attributes->getAirFriction(); + clipboard["flex"]["sen"] = attributes->getWindSensitivity(); + LLVector3 force = attributes->getUserForce(); + clipboard["flex"]["forx"] = force.mV[0]; + clipboard["flex"]["fory"] = force.mV[1]; + clipboard["flex"]["forz"] = force.mV[2]; + } + } + + // Physics + { + clipboard["physics"]["shape"] = objectp->getPhysicsShapeType(); + clipboard["physics"]["gravity"] = objectp->getPhysicsGravity(); + clipboard["physics"]["friction"] = objectp->getPhysicsFriction(); + clipboard["physics"]["density"] = objectp->getPhysicsDensity(); + clipboard["physics"]["restitution"] = objectp->getPhysicsRestitution(); + + U8 material_code = 0; + struct f : public LLSelectedTEGetFunctor<U8> + { + U8 get(LLViewerObject* object, S32 te) + { + return object->getMaterial(); + } + } func; + bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func, material_code); + // This should always be true since material should be per object. + if (material_same) + { + clipboard["physics"]["material"] = material_code; + } + } + + mClipboardParams["features"] = clipboard; +} + +void LLPanelVolume::onPasteFeatures() +{ + LLViewerObject* objectp = mObject; + if (!objectp && mClipboardParams.has("features")) + { + return; + } + + LLSD &clipboard = mClipboardParams["features"]; + + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + // Physics + bool is_root = objectp->isRoot(); + + // Not sure if phantom should go under physics, but doesn't fit elsewhere + BOOL is_phantom = clipboard["is_phantom"].asBoolean() && is_root; + LLSelectMgr::getInstance()->selectionUpdatePhantom(is_phantom); + + BOOL is_physical = clipboard["is_physical"].asBoolean() && is_root; + LLSelectMgr::getInstance()->selectionUpdatePhysics(is_physical); + + if (clipboard.has("physics")) + { + objectp->setPhysicsShapeType((U8)clipboard["physics"]["shape"].asInteger()); + U8 cur_material = objectp->getMaterial(); + U8 material = (U8)clipboard["physics"]["material"].asInteger() | (cur_material & ~LL_MCODE_MASK); + + objectp->setMaterial(material); + objectp->sendMaterialUpdate(); + objectp->setPhysicsGravity(clipboard["physics"]["gravity"].asReal()); + objectp->setPhysicsFriction(clipboard["physics"]["friction"].asReal()); + objectp->setPhysicsDensity(clipboard["physics"]["density"].asReal()); + objectp->setPhysicsRestitution(clipboard["physics"]["restitution"].asReal()); + objectp->updateFlags(TRUE); + } + + // Flexible + bool is_flexible = clipboard.has("flex"); + if (is_flexible && volobjp->canBeFlexible()) + { + LLVOVolume *volobjp = (LLVOVolume *)objectp; + BOOL update_shape = FALSE; + + // do before setParameterEntry or it will think that it is already flexi + update_shape = volobjp->setIsFlexible(is_flexible); + + if (objectp->getClickAction() == CLICK_ACTION_SIT) + { + objectp->setClickAction(CLICK_ACTION_NONE); + } + + LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + if (attributes) + { + LLFlexibleObjectData new_attributes; + new_attributes = *attributes; + new_attributes.setSimulateLOD(clipboard["flex"]["lod"].asInteger()); + new_attributes.setGravity(clipboard["flex"]["gav"].asReal()); + new_attributes.setTension(clipboard["flex"]["ten"].asReal()); + new_attributes.setAirFriction(clipboard["flex"]["fri"].asReal()); + new_attributes.setWindSensitivity(clipboard["flex"]["sen"].asReal()); + F32 fx = (F32)clipboard["flex"]["forx"].asReal(); + F32 fy = (F32)clipboard["flex"]["fory"].asReal(); + F32 fz = (F32)clipboard["flex"]["forz"].asReal(); + LLVector3 force(fx, fy, fz); + new_attributes.setUserForce(force); + objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true); + } + + if (update_shape) + { + mObject->sendShapeUpdate(); + LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom()); + } + } + else + { + LLVOVolume *volobjp = (LLVOVolume *)objectp; + if (volobjp->setIsFlexible(false)) + { + mObject->sendShapeUpdate(); + LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom()); + } + } +} + +void LLPanelVolume::onCopyLight() +{ + LLViewerObject* objectp = mObject; + if (!objectp) + { + return; + } + + LLSD clipboard; + + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + // Light Source + if (volobjp && volobjp->getIsLight()) + { + clipboard["light"]["intensity"] = volobjp->getLightIntensity(); + clipboard["light"]["radius"] = volobjp->getLightRadius(); + clipboard["light"]["falloff"] = volobjp->getLightFalloff(); + LLColor3 color = volobjp->getLightSRGBColor(); + clipboard["light"]["r"] = color.mV[0]; + clipboard["light"]["g"] = color.mV[1]; + clipboard["light"]["b"] = color.mV[2]; + + // Spotlight + if (volobjp->isLightSpotlight()) + { + LLUUID id = volobjp->getLightTextureID(); + if (id.notNull() && get_can_copy_texture(id)) + { + clipboard["spot"]["id"] = id; + LLVector3 spot_params = volobjp->getSpotLightParams(); + clipboard["spot"]["fov"] = spot_params.mV[0]; + clipboard["spot"]["focus"] = spot_params.mV[1]; + clipboard["spot"]["ambiance"] = spot_params.mV[2]; + } + } + } + + mClipboardParams["light"] = clipboard; +} + +void LLPanelVolume::onPasteLight() +{ + LLViewerObject* objectp = mObject; + if (!objectp && mClipboardParams.has("light")) + { + return; + } + + LLSD &clipboard = mClipboardParams["light"]; + + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + // Light Source + if (volobjp) + { + if (clipboard.has("light")) + { + volobjp->setIsLight(TRUE); + volobjp->setLightIntensity((F32)clipboard["light"]["intensity"].asReal()); + volobjp->setLightRadius((F32)clipboard["light"]["radius"].asReal()); + volobjp->setLightFalloff((F32)clipboard["light"]["falloff"].asReal()); + F32 r = (F32)clipboard["light"]["r"].asReal(); + F32 g = (F32)clipboard["light"]["g"].asReal(); + F32 b = (F32)clipboard["light"]["b"].asReal(); + volobjp->setLightSRGBColor(LLColor3(r, g, b)); + } + else + { + volobjp->setIsLight(FALSE); + } + + if (clipboard.has("spot")) + { + volobjp->setLightTextureID(clipboard["spot"]["id"].asUUID()); + LLVector3 spot_params; + spot_params.mV[0] = (F32)clipboard["spot"]["fov"].asReal(); + spot_params.mV[1] = (F32)clipboard["spot"]["focus"].asReal(); + spot_params.mV[2] = (F32)clipboard["spot"]["ambiance"].asReal(); + volobjp->setSpotLightParams(spot_params); + } + } +} + +void LLPanelVolume::menuDoToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste + if (command == "features_paste") + { + onPasteFeatures(); + } + else if (command == "light_paste") + { + onPasteLight(); + } + // copy + else if (command == "features_copy") + { + onCopyFeatures(); + } + else if (command == "light_copy") + { + onCopyLight(); + } +} + +bool LLPanelVolume::menuEnableItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste options + if (command == "features_paste") + { + return mClipboardParams.has("features"); + } + else if (command == "light_paste") + { + return mClipboardParams.has("light"); + } + return false; +} + // static void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) { @@ -927,6 +1284,27 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata ) } +//static +void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata) +{ + LLPanelVolume* self = (LLPanelVolume*)userdata; + LLViewerObject* objectp = self->mObject; + if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME)) + { + return; + } + LLVOVolume* volobjp = (LLVOVolume*)objectp; + + + volobjp->setReflectionProbeAmbiance((F32)self->getChild<LLUICtrl>("Probe Ambiance")->getValue().asReal()); + volobjp->setReflectionProbeNearClip((F32)self->getChild<LLUICtrl>("Probe Near Clip")->getValue().asReal()); + volobjp->setReflectionProbeIsDynamic(self->getChild<LLUICtrl>("Probe Dynamic")->getValue().asBoolean()); + + std::string shape_type = self->getChild<LLUICtrl>("Probe Volume Type")->getValue().asString(); + + volobjp->setReflectionProbeIsBox(shape_type == "Box"); +} + // static void LLPanelVolume::onCommitIsLight( LLUICtrl* ctrl, void* userdata ) { @@ -950,6 +1328,15 @@ void LLPanelVolume::setLightTextureID(const LLUUID &asset_id, const LLUUID &item //---------------------------------------------------------------------------- // static +void LLPanelVolume::onCommitIsReflectionProbe(LLUICtrl* ctrl, void* userdata) +{ + LLPanelVolume* self = (LLPanelVolume*)userdata; + self->sendIsReflectionProbe(); +} + +//---------------------------------------------------------------------------- + +// static void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata ) { LLPanelVolume* self = (LLPanelVolume*) userdata; diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 6e49ccb742..62a6d01b21 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -37,6 +37,7 @@ class LLCheckBoxCtrl; class LLTextBox; class LLUICtrl; class LLButton; +class LLMenuButton; class LLViewerObject; class LLComboBox; class LLColorSwatchCtrl; @@ -56,12 +57,15 @@ public: void refresh(); void sendIsLight(); + void sendIsReflectionProbe(); void sendIsFlexible(); static bool precommitValidate(const LLSD& data); static void onCommitIsLight( LLUICtrl* ctrl, void* userdata); static void onCommitLight( LLUICtrl* ctrl, void* userdata); + static void onCommitIsReflectionProbe(LLUICtrl* ctrl, void* userdata); + static void onCommitProbe(LLUICtrl* ctrl, void* userdata); void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata); static void onCommitFlexible( LLUICtrl* ctrl, void* userdata); void onCommitAnimatedMeshCheckbox(LLUICtrl* ctrl, void* userdata); @@ -76,6 +80,13 @@ public: static void setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp); + void onCopyFeatures(); + void onPasteFeatures(); + void onCopyLight(); + void onPasteLight(); + + void menuDoToSelected(const LLSD& userdata); + bool menuEnableItem(const LLSD& userdata); protected: void getState(); @@ -123,6 +134,11 @@ protected: LLSpinCtrl* mSpinPhysicsFriction; LLSpinCtrl* mSpinPhysicsDensity; LLSpinCtrl* mSpinPhysicsRestitution; + + LLMenuButton* mMenuClipboardFeatures; + LLMenuButton* mMenuClipboardLight; + + LLSD mClipboardParams; }; #endif diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 852b39f442..17b8ec0683 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -61,7 +61,8 @@ #define CAP_SERVICE_NAVMESH_STATUS "NavMeshGenerationStatus" -#define CAP_SERVICE_OBJECT_LINKSETS "RegionObjects" +#define CAP_SERVICE_GET_OBJECT_LINKSETS "RegionObjects" +#define CAP_SERVICE_SET_OBJECT_LINKSETS "ObjectNavMeshProperties" #define CAP_SERVICE_TERRAIN_LINKSETS "TerrainNavMeshProperties" #define CAP_SERVICE_CHARACTERS "CharacterProperties" @@ -244,7 +245,7 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re } else { - std::string objectLinksetsURL = getObjectLinksetsURLForCurrentRegion(); + std::string objectLinksetsURL = getRetrieveObjectLinksetsURLForCurrentRegion(); std::string terrainLinksetsURL = getTerrainLinksetsURLForCurrentRegion(); if (objectLinksetsURL.empty() || terrainLinksetsURL.empty()) { @@ -273,7 +274,7 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP { LLPathfindingObjectListPtr emptyLinksetListPtr; - std::string objectLinksetsURL = getObjectLinksetsURLForCurrentRegion(); + std::string objectLinksetsURL = getChangeObjectLinksetsURLForCurrentRegion(); std::string terrainLinksetsURL = getTerrainLinksetsURLForCurrentRegion(); if (objectLinksetsURL.empty() || terrainLinksetsURL.empty()) { @@ -755,9 +756,14 @@ std::string LLPathfindingManager::getRetrieveNavMeshURLForRegion(LLViewerRegion return getCapabilityURLForRegion(pRegion, CAP_SERVICE_RETRIEVE_NAVMESH); } -std::string LLPathfindingManager::getObjectLinksetsURLForCurrentRegion() const +std::string LLPathfindingManager::getRetrieveObjectLinksetsURLForCurrentRegion() const { - return getCapabilityURLForCurrentRegion(CAP_SERVICE_OBJECT_LINKSETS); + return getCapabilityURLForCurrentRegion(CAP_SERVICE_GET_OBJECT_LINKSETS); +} + +std::string LLPathfindingManager::getChangeObjectLinksetsURLForCurrentRegion() const +{ + return getCapabilityURLForCurrentRegion(CAP_SERVICE_SET_OBJECT_LINKSETS); } std::string LLPathfindingManager::getTerrainLinksetsURLForCurrentRegion() const diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h index a44cd892da..bb44f780c8 100644 --- a/indra/newview/llpathfindingmanager.h +++ b/indra/newview/llpathfindingmanager.h @@ -122,7 +122,8 @@ private: std::string getNavMeshStatusURLForCurrentRegion() const; std::string getNavMeshStatusURLForRegion(LLViewerRegion *pRegion) const; std::string getRetrieveNavMeshURLForRegion(LLViewerRegion *pRegion) const; - std::string getObjectLinksetsURLForCurrentRegion() const; + std::string getRetrieveObjectLinksetsURLForCurrentRegion() const; + std::string getChangeObjectLinksetsURLForCurrentRegion() const; std::string getTerrainLinksetsURLForCurrentRegion() const; std::string getCharactersURLForCurrentRegion() const; std::string getAgentStateURLForRegion(LLViewerRegion *pRegion) const; diff --git a/indra/newview/llplacesinventorypanel.h b/indra/newview/llplacesinventorypanel.h index 5629438415..3c27964ec5 100644 --- a/indra/newview/llplacesinventorypanel.h +++ b/indra/newview/llplacesinventorypanel.h @@ -40,7 +40,7 @@ public: { Params() { - filter_asset_type = "landmark"; + filter_asset_types = "landmark"; } }; diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 39cdb6fb04..759e7859f2 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -347,9 +347,6 @@ BOOL LLPreviewGesture::postBuild() LLTextBox* text; LLCheckBoxCtrl* check; - edit = getChild<LLLineEditor>("name"); - edit->setKeystrokeCallback(onKeystrokeCommit, this); - edit = getChild<LLLineEditor>("desc"); edit->setKeystrokeCallback(onKeystrokeCommit, this); @@ -482,9 +479,6 @@ BOOL LLPreviewGesture::postBuild() { getChild<LLUICtrl>("desc")->setValue(item->getDescription()); getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); - - getChild<LLUICtrl>("name")->setValue(item->getName()); - getChild<LLLineEditor>("name")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe); } return LLPreview::postBuild(); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index a32dc8beda..e4b4b597ca 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1199,7 +1199,7 @@ BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask) void LLScriptEdCore::onBtnLoadFromFile( void* data ) { - (new LLFilePickerReplyThread(boost::bind(&LLScriptEdCore::loadScriptFromFile, _1, data), LLFilePicker::FFLOAD_SCRIPT, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLScriptEdCore::loadScriptFromFile, _1, data), LLFilePicker::FFLOAD_SCRIPT, false); } void LLScriptEdCore::loadScriptFromFile(const std::vector<std::string>& filenames, void* data) @@ -1240,7 +1240,7 @@ void LLScriptEdCore::onBtnSaveToFile( void* userdata ) if( self->mSaveCallback ) { - (new LLFilePickerReplyThread(boost::bind(&LLScriptEdCore::saveScriptToFile, _1, userdata), LLFilePicker::FFSAVE_SCRIPT, self->mScriptName))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLScriptEdCore::saveScriptToFile, _1, userdata), LLFilePicker::FFSAVE_SCRIPT, self->mScriptName); } } diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index cd7b93aba7..7804a13cb5 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -296,7 +296,7 @@ void LLPreviewTexture::saveAs() return; std::string filename = getItem() ? LLDir::getScrubbedFileName(getItem()->getName()) : LLStringUtil::null; - (new LLFilePickerReplyThread(boost::bind(&LLPreviewTexture::saveTextureToFile, this, _1), LLFilePicker::FFSAVE_TGAPNG, filename))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLPreviewTexture::saveTextureToFile, this, _1), LLFilePicker::FFSAVE_TGAPNG, filename); } void LLPreviewTexture::saveTextureToFile(const std::vector<std::string>& filenames) diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp new file mode 100644 index 0000000000..2a7ab84501 --- /dev/null +++ b/indra/newview/llreflectionmap.cpp @@ -0,0 +1,269 @@ +/** + * @file llreflectionmap.cpp + * @brief LLReflectionMap class implementation + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 "llviewerprecompiledheaders.h" + +#include "llreflectionmap.h" +#include "pipeline.h" +#include "llviewerwindow.h" +#include "llviewerregion.h" + +extern F32SecondsImplicit gFrameTimeSeconds; + +LLReflectionMap::LLReflectionMap() +{ +} + +void LLReflectionMap::update(U32 resolution, U32 face) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + mLastUpdateTime = gFrameTimeSeconds; + llassert(mCubeArray.notNull()); + llassert(mCubeIndex != -1); + llassert(LLPipeline::sRenderDeferred); + + // make sure we don't walk off the edge of the render target + while (resolution > gPipeline.mRT->deferredScreen.getWidth() || + resolution > gPipeline.mRT->deferredScreen.getHeight()) + { + resolution /= 2; + } + gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, getNearClip(), getIsDynamic()); +} + +void LLReflectionMap::autoAdjustOrigin() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + + if (mGroup) + { + const LLVector4a* bounds = mGroup->getBounds(); + auto* node = mGroup->getOctreeNode(); + + if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_TERRAIN) + { + // for terrain, make probes float a couple meters above the highest point in the surface patch + mOrigin = bounds[0]; + mOrigin.getF32ptr()[2] += bounds[1].getF32ptr()[2] + 3.f; + + // update radius to encompass bounding box + LLVector4a d; + d.setAdd(bounds[0], bounds[1]); + d.sub(mOrigin); + mRadius = d.getLength3().getF32(); + mPriority = 1; + } + else if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME) + { + mPriority = 1; + // cast a ray towards 8 corners of bounding box + // nudge origin towards center of empty space + + if (node->isLeaf() || node->getChildCount() > 1 || node->getData().size() > 0) + { // use center of object bounding box for leaf nodes or nodes with multiple child nodes + mOrigin = bounds[0]; + + LLVector4a start; + LLVector4a end; + + LLVector4a size = bounds[1]; + + LLVector4a corners[] = + { + { 1, 1, 1 }, + { -1, 1, 1 }, + { 1, -1, 1 }, + { -1, -1, 1 }, + { 1, 1, -1 }, + { -1, 1, -1 }, + { 1, -1, -1 }, + { -1, -1, -1 } + }; + + for (int i = 0; i < 8; ++i) + { + corners[i].mul(size); + corners[i].add(bounds[0]); + } + + LLVector4a extents[2]; + extents[0].setAdd(bounds[0], bounds[1]); + extents[1].setSub(bounds[0], bounds[1]); + + bool hit = false; + for (int i = 0; i < 8; ++i) + { + int face = -1; + LLVector4a intersection; + LLDrawable* drawable = mGroup->lineSegmentIntersect(bounds[0], corners[i], true, false, true, &face, &intersection); + if (drawable != nullptr) + { + hit = true; + update_min_max(extents[0], extents[1], intersection); + } + else + { + update_min_max(extents[0], extents[1], corners[i]); + } + } + + if (hit) + { + mOrigin.setAdd(extents[0], extents[1]); + mOrigin.mul(0.5f); + } + + // make sure radius encompasses all objects + LLSimdScalar r2 = 0.0; + for (int i = 0; i < 8; ++i) + { + LLVector4a v; + v.setSub(corners[i], mOrigin); + + LLSimdScalar d = v.dot3(v); + + if (d > r2) + { + r2 = d; + } + } + + mRadius = llmax(sqrtf(r2.getF32()), 8.f); + } + else + { + // user placed probe + mPriority = 2; + + // use center of octree node volume for nodes that are just branches without data + mOrigin = node->getCenter(); + + // update radius to encompass entire octree node volume + mRadius = node->getSize().getLength3().getF32(); + + //mOrigin = bounds[0]; + //mRadius = bounds[1].getLength3().getF32(); + + } + } + } + else if (mViewerObject) + { + mPriority = 64; + mOrigin.load3(mViewerObject->getPositionAgent().mV); + mRadius = mViewerObject->getScale().mV[0]*0.5f; + } +} + +bool LLReflectionMap::intersects(LLReflectionMap* other) +{ + // TODO: incorporate getBox + LLVector4a delta; + delta.setSub(other->mOrigin, mOrigin); + + F32 dist = delta.dot3(delta).getF32(); + + F32 r2 = mRadius + other->mRadius; + + r2 *= r2; + + return dist < r2; +} + +extern LLControlGroup gSavedSettings; + +F32 LLReflectionMap::getAmbiance() +{ + F32 ret = 0.f; + if (mViewerObject && mViewerObject->getVolume()) + { + ret = ((LLVOVolume*)mViewerObject)->getReflectionProbeAmbiance(); + } + + return ret; +} + +F32 LLReflectionMap::getNearClip() +{ + const F32 MINIMUM_NEAR_CLIP = 0.1f; + + F32 ret = 0.f; + + if (mViewerObject && mViewerObject->getVolume()) + { + ret = ((LLVOVolume*)mViewerObject)->getReflectionProbeNearClip(); + } + + return llmax(ret, MINIMUM_NEAR_CLIP); +} + +bool LLReflectionMap::getIsDynamic() +{ + if (gSavedSettings.getS32("RenderReflectionProbeDetail") > (S32) LLReflectionMapManager::DetailLevel::STATIC_ONLY && + mViewerObject && + mViewerObject->getVolume()) + { + return ((LLVOVolume*)mViewerObject)->getReflectionProbeIsDynamic(); + } + + return false; +} + +bool LLReflectionMap::getBox(LLMatrix4& box) +{ + if (mViewerObject) + { + LLVolume* volume = mViewerObject->getVolume(); + if (volume) + { + LLVOVolume* vobjp = (LLVOVolume*)mViewerObject; + + if (vobjp->getReflectionProbeIsBox()) + { + glh::matrix4f mv(gGLModelView); + glh::matrix4f scale; + LLVector3 s = vobjp->getScale().scaledVec(LLVector3(0.5f, 0.5f, 0.5f)); + mRadius = s.magVec(); + scale.set_scale(glh::vec3f(s.mV)); + if (vobjp->mDrawable != nullptr) + { + glh::matrix4f rm((F32*)vobjp->mDrawable->getWorldMatrix().mMatrix); + + glh::matrix4f rt((F32*)vobjp->getRelativeXform().mMatrix); + + mv = mv * rm * scale; // *rt; + mv = mv.inverse(); + + box = LLMatrix4(mv.m); + + return true; + } + } + } + } + + return false; +} diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h new file mode 100644 index 0000000000..cf0bc2ff27 --- /dev/null +++ b/indra/newview/llreflectionmap.h @@ -0,0 +1,102 @@ +/** + * @file llreflectionmap.h + * @brief LLReflectionMap class declaration + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 + +#include "llcubemaparray.h" +#include "llmemory.h" + +class LLSpatialGroup; +class LLViewerObject; + +class alignas(16) LLReflectionMap : public LLRefCount +{ + LL_ALIGN_NEW +public: + // allocate an environment map of the given resolution + LLReflectionMap(); + + // update this environment map + // resolution - size of cube map to generate + void update(U32 resolution, U32 face); + + // for volume partition probes, try to place this probe in the best spot + void autoAdjustOrigin(); + + // return true if given Reflection Map's influence volume intersect's with this one's + bool intersects(LLReflectionMap* other); + + // Get the ambiance value to use for this probe + F32 getAmbiance(); + + // Get the near clip plane distance to use for this probe + F32 getNearClip(); + + // Return true if this probe should include avatars in its reflection map + bool getIsDynamic(); + + // get the encoded bounding box of this probe's influence volume + // will only return a box if this probe is associated with a VOVolume + // with its reflection probe influence volume to to VOLUME_TYPE_BOX + // return false if no bounding box (treat as sphere influence volume) + bool getBox(LLMatrix4& box); + + // point at which environment map was last generated from (in agent space) + LLVector4a mOrigin; + + // distance from viewer camera + F32 mDistance; + + // radius of this probe's affected area + F32 mRadius = 16.f; + + // last time this probe was updated (or when its update timer got reset) + F32 mLastUpdateTime = 0.f; + + // last time this probe was bound for rendering + F32 mLastBindTime = 0.f; + + // cube map used to sample this environment map + LLPointer<LLCubeMapArray> mCubeArray; + S32 mCubeIndex = -1; // index into cube map array or -1 if not currently stored in cube map array + + // index into array packed by LLReflectionMapManager::getReflectionMaps + // WARNING -- only valid immediately after call to getReflectionMaps + S32 mProbeIndex = -1; + + // set of any LLReflectionMaps that intersect this map (maintained by LLReflectionMapManager + std::vector<LLReflectionMap*> mNeighbors; + + // spatial group this probe is tracking (if any) + LLSpatialGroup* mGroup = nullptr; + + // viewer object this probe is tracking (if any) + LLViewerObject* mViewerObject = nullptr; + + // what priority should this probe have (higher is higher priority) + U32 mPriority = 1; +}; + diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp new file mode 100644 index 0000000000..b285cc531e --- /dev/null +++ b/indra/newview/llreflectionmapmanager.cpp @@ -0,0 +1,839 @@ +/** + * @file llreflectionmapmanager.cpp + * @brief LLReflectionMapManager class implementation + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 "llviewerprecompiledheaders.h" + +#include "llreflectionmapmanager.h" +#include "llviewercamera.h" +#include "llspatialpartition.h" +#include "llviewerregion.h" +#include "pipeline.h" +#include "llviewershadermgr.h" +#include "llviewercontrol.h" +#include "llenvironment.h" + +extern BOOL gCubeSnapshot; +extern BOOL gTeleportDisplay; + +LLReflectionMapManager::LLReflectionMapManager() +{ + for (int i = 0; i < LL_MAX_REFLECTION_PROBE_COUNT; ++i) + { + mCubeFree[i] = true; + } +} + +struct CompareReflectionMapDistance +{ + +}; + + +struct CompareProbeDistance +{ + bool operator()(const LLPointer<LLReflectionMap>& lhs, const LLPointer<LLReflectionMap>& rhs) + { + return lhs->mDistance < rhs->mDistance; + } +}; + +// helper class to seed octree with probes +void LLReflectionMapManager::update() +{ + if (!LLPipeline::sRenderPBR || gTeleportDisplay) + { + return; + } + + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + llassert(!gCubeSnapshot); // assert a snapshot is not in progress + if (LLAppViewer::instance()->logoutRequestSent()) + { + return; + } + + // =============== TODO -- move to an init function ================= + initReflectionMaps(); + + if (!mRenderTarget.isComplete()) + { + U32 color_fmt = GL_RGBA; + const bool use_depth_buffer = true; + const bool use_stencil_buffer = true; + U32 targetRes = LL_REFLECTION_PROBE_RESOLUTION * 2; // super sample + mRenderTarget.allocate(targetRes, targetRes, color_fmt, use_depth_buffer, use_stencil_buffer, LLTexUnit::TT_RECT_TEXTURE); + } + + if (mMipChain.empty()) + { + U32 res = LL_REFLECTION_PROBE_RESOLUTION; + U32 count = log2((F32)res) + 0.5f; + + mMipChain.resize(count); + for (int i = 0; i < count; ++i) + { + mMipChain[i].allocate(res, res, GL_RGB, false, false, LLTexUnit::TT_RECT_TEXTURE); + res /= 2; + } + } + + + LLVector4a camera_pos; + camera_pos.load3(LLViewerCamera::instance().getOrigin().mV); + + // process kill list + for (auto& probe : mKillList) + { + auto const & iter = std::find(mProbes.begin(), mProbes.end(), probe); + if (iter != mProbes.end()) + { + deleteProbe(iter - mProbes.begin()); + } + } + + mKillList.clear(); + + // process create list + for (auto& probe : mCreateList) + { + mProbes.push_back(probe); + } + + mCreateList.clear(); + + if (mProbes.empty()) + { + return; + } + + bool did_update = false; + + bool realtime = gSavedSettings.getS32("RenderReflectionProbeDetail") >= (S32)LLReflectionMapManager::DetailLevel::REALTIME; + + LLReflectionMap* closestDynamic = nullptr; + + LLReflectionMap* oldestProbe = nullptr; + + if (mUpdatingProbe != nullptr) + { + did_update = true; + doProbeUpdate(); + } + + for (int i = 0; i < mProbes.size(); ++i) + { + LLReflectionMap* probe = mProbes[i]; + if (probe->getNumRefs() == 1) + { // no references held outside manager, delete this probe + deleteProbe(i); + --i; + continue; + } + + probe->mProbeIndex = i; + + LLVector4a d; + + if (!did_update && + i < mReflectionProbeCount && + (oldestProbe == nullptr || probe->mLastUpdateTime < oldestProbe->mLastUpdateTime)) + { + oldestProbe = probe; + } + + if (realtime && + closestDynamic == nullptr && + probe->mCubeArray.notNull() && + probe->getIsDynamic()) + { + closestDynamic = probe; + } + + d.setSub(camera_pos, probe->mOrigin); + probe->mDistance = d.getLength3().getF32()-probe->mRadius; + } + + if (realtime && closestDynamic != nullptr) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmu - realtime"); + // update the closest dynamic probe realtime + closestDynamic->autoAdjustOrigin(); + for (U32 i = 0; i < 6; ++i) + { + updateProbeFace(closestDynamic, i); + } + } + + // switch to updating the next oldest probe + if (!did_update && oldestProbe != nullptr) + { + LLReflectionMap* probe = oldestProbe; + if (probe->mCubeIndex == -1) + { + probe->mCubeArray = mTexture; + probe->mCubeIndex = allocateCubeIndex(); + } + + probe->autoAdjustOrigin(); + + mUpdatingProbe = probe; + doProbeUpdate(); + } + + // update distance to camera for all probes + std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance()); +} + +LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group) +{ + LLReflectionMap* probe = new LLReflectionMap(); + probe->mGroup = group; + probe->mOrigin = group->getOctreeNode()->getCenter(); + + if (gCubeSnapshot) + { //snapshot is in progress, mProbes is being iterated over, defer insertion until next update + mCreateList.push_back(probe); + } + else + { + mProbes.push_back(probe); + } + + return probe; +} + +void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& maps) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + + U32 count = 0; + U32 lastIdx = 0; + for (U32 i = 0; count < maps.size() && i < mProbes.size(); ++i) + { + mProbes[i]->mLastBindTime = gFrameTimeSeconds; // something wants to use this probe, indicate it's been requested + if (mProbes[i]->mCubeIndex != -1) + { + mProbes[i]->mProbeIndex = count; + maps[count++] = mProbes[i]; + } + else + { + mProbes[i]->mProbeIndex = -1; + } + lastIdx = i; + } + + // set remaining probe indices to -1 + for (U32 i = lastIdx+1; i < mProbes.size(); ++i) + { + mProbes[i]->mProbeIndex = -1; + } + + // null terminate list + if (count < maps.size()) + { + maps[count] = nullptr; + } +} + +LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* group) +{ +#if 1 + if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME) + { + OctreeNode* node = group->getOctreeNode(); + F32 size = node->getSize().getF32ptr()[0]; + if (size >= 15.f && size <= 17.f) + { + return addProbe(group); + } + } + + if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_TERRAIN) + { + OctreeNode* node = group->getOctreeNode(); + F32 size = node->getSize().getF32ptr()[0]; + if (size >= 15.f && size <= 17.f) + { + return addProbe(group); + } + } +#endif + return nullptr; +} + +LLReflectionMap* LLReflectionMapManager::registerViewerObject(LLViewerObject* vobj) +{ + llassert(vobj != nullptr); + + LLReflectionMap* probe = new LLReflectionMap(); + probe->mViewerObject = vobj; + probe->mOrigin.load3(vobj->getPositionAgent().mV); + + if (gCubeSnapshot) + { //snapshot is in progress, mProbes is being iterated over, defer insertion until next update + mCreateList.push_back(probe); + } + else + { + mProbes.push_back(probe); + } + + return probe; +} + + +S32 LLReflectionMapManager::allocateCubeIndex() +{ + for (int i = 0; i < mReflectionProbeCount; ++i) + { + if (mCubeFree[i]) + { + mCubeFree[i] = false; + return i; + } + } + + // no cubemaps free, steal one from the back of the probe list + for (int i = mProbes.size() - 1; i >= mReflectionProbeCount; --i) + { + if (mProbes[i]->mCubeIndex != -1) + { + S32 ret = mProbes[i]->mCubeIndex; + mProbes[i]->mCubeIndex = -1; + return ret; + } + } + + llassert(false); // should never fail to allocate, something is probably wrong with mCubeFree + return -1; +} + +void LLReflectionMapManager::deleteProbe(U32 i) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + LLReflectionMap* probe = mProbes[i]; + + if (probe->mCubeIndex != -1) + { // mark the cube index used by this probe as being free + mCubeFree[probe->mCubeIndex] = true; + } + if (mUpdatingProbe == probe) + { + mUpdatingProbe = nullptr; + mUpdatingFace = 0; + } + + // remove from any Neighbors lists + for (auto& other : probe->mNeighbors) + { + auto const & iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe); + llassert(iter != other->mNeighbors.end()); + other->mNeighbors.erase(iter); + } + + mProbes.erase(mProbes.begin() + i); +} + + +void LLReflectionMapManager::doProbeUpdate() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + llassert(mUpdatingProbe != nullptr); + + updateProbeFace(mUpdatingProbe, mUpdatingFace); + + if (++mUpdatingFace == 6) + { + updateNeighbors(mUpdatingProbe); + mUpdatingProbe = nullptr; + mUpdatingFace = 0; + } +} + +void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) +{ + mRenderTarget.bindTarget(); + // hacky hot-swap of camera specific render targets + gPipeline.mRT = &gPipeline.mAuxillaryRT; + probe->update(mRenderTarget.getWidth(), face); + gPipeline.mRT = &gPipeline.mMainRT; + mRenderTarget.flush(); + + S32 targetIdx = mReflectionProbeCount; + + if (probe != mUpdatingProbe) + { // this is the "realtime" probe that's updating every frame, use the secondary scratch space channel + targetIdx += 1; + } + + // downsample to placeholder map + { + LLGLDepthTest depth(GL_FALSE, GL_FALSE); + LLGLDisable cull(GL_CULL_FACE); + + gReflectionMipProgram.bind(); + gGL.matrixMode(gGL.MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); + + gGL.matrixMode(gGL.MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + gGL.flush(); + U32 res = LL_REFLECTION_PROBE_RESOLUTION * 2; + + S32 mips = log2((F32)LL_REFLECTION_PROBE_RESOLUTION) + 0.5f; + + //for (int i = 0; i < mMipChain.size(); ++i) + for (int i = 0; i < 1; ++i) + { + LL_PROFILE_GPU_ZONE("probe mip"); + mMipChain[i].bindTarget(); + + if (i == 0) + { + gGL.getTexUnit(0)->bind(&mRenderTarget); + } + else + { + gGL.getTexUnit(0)->bind(&(mMipChain[i - 1])); + } + + gGL.begin(gGL.QUADS); + + gGL.texCoord2f(0, 0); + gGL.vertex2f(-1, -1); + + gGL.texCoord2f(res, 0); + gGL.vertex2f(1, -1); + + gGL.texCoord2f(res, res); + gGL.vertex2f(1, 1); + + gGL.texCoord2f(0, res); + gGL.vertex2f(-1, 1); + gGL.end(); + gGL.flush(); + + res /= 2; + + S32 mip = i - (mMipChain.size() - mips); + + if (mip >= 0) + { + mTexture->bind(0); + //glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res); + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, targetIdx * 6 + face, 0, 0, res, res); + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, probe->mCubeIndex * 6 + face, 0, 0, res, res); + mTexture->unbind(); + } + mMipChain[i].flush(); + } + + gGL.popMatrix(); + gGL.matrixMode(gGL.MM_MODELVIEW); + gGL.popMatrix(); + + gReflectionMipProgram.unbind(); + } + + if (face == 5) + { + //generate radiance map + gRadianceGenProgram.bind(); + S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); + mTexture->bind(channel); + static LLStaticHashedString sSourceIdx("sourceIdx"); + gRadianceGenProgram.uniform1i(sSourceIdx, targetIdx); + + static LLStaticHashedString sMipLevel("mipLevel"); + + for (int i = 1; i < mMipChain.size(); ++i) + { + for (int cf = 0; cf < 6; ++cf) + { // for each cube face + LLCoordFrame frame; + frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]); + + F32 mat[16]; + frame.getOpenGLRotation(mat); + gGL.loadMatrix(mat); + + mMipChain[i].bindTarget(); + static LLStaticHashedString sRoughness("roughness"); + + gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1)); + gRadianceGenProgram.uniform1f(sMipLevel, llmax((F32)(i - 1), 0.f)); + if (i > 0) + { + gRadianceGenProgram.uniform1i(sSourceIdx, probe->mCubeIndex); + } + gGL.begin(gGL.QUADS); + gGL.vertex3f(-1, -1, -1); + gGL.vertex3f(1, -1, -1); + gGL.vertex3f(1, 1, -1); + gGL.vertex3f(-1, 1, -1); + gGL.end(); + gGL.flush(); + + S32 res = mMipChain[i].getWidth(); + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res); + mMipChain[i].flush(); + } + } + gRadianceGenProgram.unbind(); + + //generate irradiance map + gIrradianceGenProgram.bind(); + channel = gIrradianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); + mTexture->bind(channel); + + gIrradianceGenProgram.uniform1i(sSourceIdx, probe->mCubeIndex); + + int start_mip = 0; + // find the mip target to start with based on irradiance map resolution + for (start_mip = 0; start_mip < mMipChain.size(); ++start_mip) + { + if (mMipChain[start_mip].getWidth() == LL_IRRADIANCE_MAP_RESOLUTION) + { + break; + } + } + + for (int i = start_mip; i < mMipChain.size(); ++i) + { + for (int cf = 0; cf < 6; ++cf) + { // for each cube face + LLCoordFrame frame; + frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]); + + F32 mat[16]; + frame.getOpenGLRotation(mat); + gGL.loadMatrix(mat); + + mMipChain[i].bindTarget(); + + gGL.begin(gGL.QUADS); + gGL.vertex3f(-1, -1, -1); + gGL.vertex3f(1, -1, -1); + gGL.vertex3f(1, 1, -1); + gGL.vertex3f(-1, 1, -1); + gGL.end(); + gGL.flush(); + + S32 res = mMipChain[i].getWidth(); + mIrradianceMaps->bind(channel); + glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i - start_mip, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res); + mTexture->bind(channel); + mMipChain[i].flush(); + } + } + gIrradianceGenProgram.unbind(); + } +} + +void LLReflectionMapManager::rebuild() +{ + for (auto& probe : mProbes) + { + probe->mLastUpdateTime = 0.f; + } +} + +void LLReflectionMapManager::shift(const LLVector4a& offset) +{ + for (auto& probe : mProbes) + { + probe->mOrigin.add(offset); + } +} + +void LLReflectionMapManager::updateNeighbors(LLReflectionMap* probe) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + + //remove from existing neighbors + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear"); + + for (auto& other : probe->mNeighbors) + { + auto const & iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe); + llassert(iter != other->mNeighbors.end()); // <--- bug davep if this ever happens, something broke badly + other->mNeighbors.erase(iter); + } + + probe->mNeighbors.clear(); + } + + // search for new neighbors + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - search"); + for (auto& other : mProbes) + { + if (other != probe) + { + if (probe->intersects(other)) + { + probe->mNeighbors.push_back(other); + other->mNeighbors.push_back(probe); + } + } + } + } +} + +void LLReflectionMapManager::updateUniforms() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + + // structure for packing uniform buffer object + // see class3/deferred/reflectionProbeF.glsl + struct ReflectionProbeData + { + LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT]; // object bounding box as needed + LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT]; //origin and radius of refmaps in clip space + LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT]; //extra parameters (currently only ambiance) + GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4]; + GLint refNeighbor[4096]; + GLint refmapCount; + }; + + mReflectionMaps.resize(mReflectionProbeCount); + getReflectionMaps(mReflectionMaps); + + ReflectionProbeData rpd; + + // load modelview matrix into matrix 4a + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + LLVector4a oa; // scratch space for transformed origin + + S32 count = 0; + U32 nc = 0; // neighbor "cursor" - index into refNeighbor to start writing the next probe's list of neighbors + + LLEnvironment& environment = LLEnvironment::instance(); + LLSettingsSky::ptr_t psky = environment.getCurrentSky(); + + F32 minimum_ambiance = psky->getReflectionProbeAmbiance(); + + for (auto* refmap : mReflectionMaps) + { + if (refmap == nullptr) + { + break; + } + + llassert(refmap->mProbeIndex == count); + llassert(mReflectionMaps[refmap->mProbeIndex] == refmap); + + llassert(refmap->mCubeIndex >= 0); // should always be true, if not, getReflectionMaps is bugged + + { + //LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - refSphere"); + + modelview.affineTransform(refmap->mOrigin, oa); + rpd.refSphere[count].set(oa.getF32ptr()); + rpd.refSphere[count].mV[3] = refmap->mRadius; + } + + rpd.refIndex[count][0] = refmap->mCubeIndex; + llassert(nc % 4 == 0); + rpd.refIndex[count][1] = nc / 4; + rpd.refIndex[count][3] = refmap->mPriority; + + // for objects that are reflection probes, use the volume as the influence volume of the probe + // only possibile influence volumes are boxes and spheres, so detect boxes and treat everything else as spheres + if (refmap->getBox(rpd.refBox[count])) + { // negate priority to indicate this probe has a box influence volume + rpd.refIndex[count][3] = -rpd.refIndex[count][3]; + } + + rpd.refParams[count].set(llmax(minimum_ambiance, refmap->getAmbiance()), 0.f, 0.f, 0.f); + + S32 ni = nc; // neighbor ("index") - index into refNeighbor to write indices for current reflection probe's neighbors + { + //LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - refNeighbors"); + //pack neghbor list + for (auto& neighbor : refmap->mNeighbors) + { + if (ni >= 4096) + { // out of space + break; + } + + GLint idx = neighbor->mProbeIndex; + if (idx == -1) + { + continue; + } + + // this neighbor may be sampled + rpd.refNeighbor[ni++] = idx; + } + } + + if (nc == ni) + { + //no neighbors, tag as empty + rpd.refIndex[count][1] = -1; + } + else + { + rpd.refIndex[count][2] = ni - nc; + + // move the cursor forward + nc = ni; + if (nc % 4 != 0) + { // jump to next power of 4 for compatibility with ivec4 + nc += 4 - (nc % 4); + } + } + + + count++; + } + + rpd.refmapCount = count; + + //copy rpd into uniform buffer object + if (mUBO == 0) + { + glGenBuffersARB(1, &mUBO); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - update buffer"); + glBindBufferARB(GL_UNIFORM_BUFFER, mUBO); + glBufferDataARB(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeData), &rpd, GL_STREAM_DRAW); + glBindBufferARB(GL_UNIFORM_BUFFER, 0); + } +} + +void LLReflectionMapManager::setUniforms() +{ + llassert(LLPipeline::sRenderPBR); + if (mUBO == 0) + { + updateUniforms(); + } + glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO); +} + + +void renderReflectionProbe(LLReflectionMap* probe) +{ + F32* po = probe->mOrigin.getF32ptr(); + + //draw orange line from probe to neighbors + gGL.flush(); + gGL.diffuseColor4f(1, 0.5f, 0, 1); + gGL.begin(gGL.LINES); + for (auto& neighbor : probe->mNeighbors) + { + gGL.vertex3fv(po); + gGL.vertex3fv(neighbor->mOrigin.getF32ptr()); + } + gGL.end(); + gGL.flush(); + +#if 0 + LLSpatialGroup* group = probe->mGroup; + if (group) + { // draw lines from corners of object aabb to reflection probe + + const LLVector4a* bounds = group->getBounds(); + LLVector4a o = bounds[0]; + + gGL.flush(); + gGL.diffuseColor4f(0, 0, 1, 1); + F32* c = o.getF32ptr(); + + const F32* bc = bounds[0].getF32ptr(); + const F32* bs = bounds[1].getF32ptr(); + + // daaw blue lines from corners to center of node + gGL.begin(gGL.LINES); + gGL.vertex3fv(c); + gGL.vertex3f(bc[0] + bs[0], bc[1] + bs[1], bc[2] + bs[2]); + gGL.vertex3fv(c); + gGL.vertex3f(bc[0] - bs[0], bc[1] + bs[1], bc[2] + bs[2]); + gGL.vertex3fv(c); + gGL.vertex3f(bc[0] + bs[0], bc[1] - bs[1], bc[2] + bs[2]); + gGL.vertex3fv(c); + gGL.vertex3f(bc[0] - bs[0], bc[1] - bs[1], bc[2] + bs[2]); + + gGL.vertex3fv(c); + gGL.vertex3f(bc[0] + bs[0], bc[1] + bs[1], bc[2] - bs[2]); + gGL.vertex3fv(c); + gGL.vertex3f(bc[0] - bs[0], bc[1] + bs[1], bc[2] - bs[2]); + gGL.vertex3fv(c); + gGL.vertex3f(bc[0] + bs[0], bc[1] - bs[1], bc[2] - bs[2]); + gGL.vertex3fv(c); + gGL.vertex3f(bc[0] - bs[0], bc[1] - bs[1], bc[2] - bs[2]); + gGL.end(); + + //draw yellow line from center of node to reflection probe origin + gGL.flush(); + gGL.diffuseColor4f(1, 1, 0, 1); + gGL.begin(gGL.LINES); + gGL.vertex3fv(c); + gGL.vertex3fv(po); + gGL.end(); + gGL.flush(); + } +#endif +} + +void LLReflectionMapManager::renderDebug() +{ + gDebugProgram.bind(); + + for (auto& probe : mProbes) + { + renderReflectionProbe(probe); + } + + gDebugProgram.unbind(); +} + +void LLReflectionMapManager::initReflectionMaps() +{ + if (mTexture.isNull()) + { + mReflectionProbeCount = llclamp(gSavedSettings.getS32("RenderReflectionProbeCount"), 1, LL_MAX_REFLECTION_PROBE_COUNT); + + mTexture = new LLCubeMapArray(); + + // store mReflectionProbeCount+2 cube maps, final two cube maps are used for render target and radiance map generation source) + mTexture->allocate(LL_REFLECTION_PROBE_RESOLUTION, 3, mReflectionProbeCount + 2); + + mIrradianceMaps = new LLCubeMapArray(); + mIrradianceMaps->allocate(LL_IRRADIANCE_MAP_RESOLUTION, 3, mReflectionProbeCount); + } +} diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h new file mode 100644 index 0000000000..29a9ece2f8 --- /dev/null +++ b/indra/newview/llreflectionmapmanager.h @@ -0,0 +1,158 @@ +/** + * @file llreflectionmapmanager.h + * @brief LLReflectionMapManager class declaration + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 + +#include "llreflectionmap.h" +#include "llrendertarget.h" +#include "llcubemaparray.h" +#include "llcubemap.h" + +class LLSpatialGroup; +class LLViewerObject; + +// number of reflection probes to keep in vram +#define LL_MAX_REFLECTION_PROBE_COUNT 256 + +// reflection probe resolution +#define LL_REFLECTION_PROBE_RESOLUTION 256 +#define LL_IRRADIANCE_MAP_RESOLUTION 64 + +// reflection probe mininum scale +#define LL_REFLECTION_PROBE_MINIMUM_SCALE 1.f; + +class alignas(16) LLReflectionMapManager +{ + LL_ALIGN_NEW +public: + enum class DetailLevel + { + STATIC_ONLY = 0, + STATIC_AND_DYNAMIC, + REALTIME = 2 + }; + + // allocate an environment map of the given resolution + LLReflectionMapManager(); + + // maintain reflection probes + void update(); + + // add a probe for the given spatial group + LLReflectionMap* addProbe(LLSpatialGroup* group); + + // Populate "maps" with the N most relevant Reflection Maps where N is no more than maps.size() + // If less than maps.size() ReflectionMaps are available, will assign trailing elements to nullptr. + // maps -- presized array of Reflection Map pointers + void getReflectionMaps(std::vector<LLReflectionMap*>& maps); + + // called by LLSpatialGroup constructor + // If spatial group should receive a Reflection Probe, will create one for the specified spatial group + LLReflectionMap* registerSpatialGroup(LLSpatialGroup* group); + + // presently hacked into LLViewerObject::setTE + // Used by LLViewerObjects that are Reflection Probes + // Guaranteed to not return null + LLReflectionMap* registerViewerObject(LLViewerObject* vobj); + + // force an update of all probes + void rebuild(); + + // called on region crossing to "shift" probes into new coordinate frame + void shift(const LLVector4a& offset); + + // debug display, called from llspatialpartition if reflection + // probe debug display is active + void renderDebug(); + + // call once at startup to allocate cubemap arrays + void initReflectionMaps(); + +private: + friend class LLPipeline; + + // delete the probe with the given index in mProbes + void deleteProbe(U32 i); + + // get a free cube index + // if no cube indices are free, free one starting from the back of the probe list + S32 allocateCubeIndex(); + + // update the neighbors of the given probe + void updateNeighbors(LLReflectionMap* probe); + + // update UBO used for rendering (call only once per render pipe flush) + void updateUniforms(); + + // bind UBO used for rendering + void setUniforms(); + + // render target for cube snapshots + // used to generate mipmaps without doing a copy-to-texture + LLRenderTarget mRenderTarget; + + std::vector<LLRenderTarget> mMipChain; + + // storage for reflection probe radiance maps (plus two scratch space cubemaps) + LLPointer<LLCubeMapArray> mTexture; + + // storage for reflection probe irradiance maps + LLPointer<LLCubeMapArray> mIrradianceMaps; + + // array indicating if a particular cubemap is free + bool mCubeFree[LL_MAX_REFLECTION_PROBE_COUNT]; + + // start tracking the given spatial group + void trackGroup(LLSpatialGroup* group); + + // perform an update on the currently updating Probe + void doProbeUpdate(); + + // update the specified face of the specified probe + void updateProbeFace(LLReflectionMap* probe, U32 face); + + // list of active reflection maps + std::vector<LLPointer<LLReflectionMap> > mProbes; + + // list of reflection maps to kill + std::vector<LLPointer<LLReflectionMap> > mKillList; + + // list of reflection maps to create + std::vector<LLPointer<LLReflectionMap> > mCreateList; + + // handle to UBO + U32 mUBO = 0; + + // list of maps being used for rendering + std::vector<LLReflectionMap*> mReflectionMaps; + + LLReflectionMap* mUpdatingProbe = nullptr; + U32 mUpdatingFace = 0; + + // number of reflection probes to use for rendering (based on saved setting RenderReflectionProbeCount) + U32 mReflectionProbeCount; +}; + diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 82a165cb35..fc5b1c60e2 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1066,8 +1066,8 @@ void LLSelectMgr::highlightObjectOnly(LLViewerObject* objectp) return; } - if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !objectp->permYouOwner()) - || (gSavedSettings.getBOOL("SelectMovableOnly") && (!objectp->permMove() || objectp->isPermanentEnforced()))) + if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !objectp->permYouOwner()) + || (gSavedSettings.getBOOL("SelectMovableOnly") && (!objectp->permMove() || objectp->isPermanentEnforced()))) { // only select my own objects return; @@ -1936,6 +1936,32 @@ BOOL LLSelectMgr::selectionRevertTextures() return revert_successful; } +void LLSelectMgr::selectionRevertGLTFMaterials() +{ + struct f : public LLSelectedTEFunctor + { + LLObjectSelectionHandle mSelectedObjects; + f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + LLSelectNode* nodep = mSelectedObjects->findNode(object); + if (nodep && te < (S32)nodep->mSavedGLTFMaterials.size()) + { + LLUUID id = nodep->mSavedGLTFMaterials[te]; + object->setRenderMaterialID(te, id); + } + } + return true; + } + } setfunc(mSelectedObjects); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + void LLSelectMgr::selectionSetBumpmap(U8 bumpmap, const LLUUID &image_id) { struct f : public LLSelectedTEFunctor @@ -5526,6 +5552,17 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data // this should be the only place that saved textures is called node->saveTextures(texture_ids); } + + if (can_copy && can_transfer && node->getObject()->getVolume()) + { + uuid_vec_t material_ids; + LLVOVolume* vobjp = (LLVOVolume*)node->getObject(); + for (int i = 0; i < vobjp->getNumTEs(); ++i) + { + material_ids.push_back(vobjp->getRenderMaterialID(i)); + } + node->savedGLTFMaterials(material_ids); + } } node->mValid = TRUE; @@ -6277,6 +6314,7 @@ LLSelectNode::LLSelectNode(const LLSelectNode& nodep) } saveTextures(nodep.mSavedTextures); + savedGLTFMaterials(nodep.mSavedGLTFMaterials); } LLSelectNode::~LLSelectNode() @@ -6392,6 +6430,20 @@ void LLSelectNode::saveTextures(const uuid_vec_t& textures) } } +void LLSelectNode::savedGLTFMaterials(const uuid_vec_t& materials) +{ + if (mObject.notNull()) + { + mSavedGLTFMaterials.clear(); + + for (uuid_vec_t::const_iterator materials_it = materials.begin(); + materials_it != materials.end(); ++materials_it) + { + mSavedGLTFMaterials.push_back(*materials_it); + } + } +} + void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query) { mTextureScaleRatios.clear(); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index ce0316e610..aec2baa6a7 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -187,6 +187,7 @@ public: void saveColors(); void saveShinyColors(); void saveTextures(const uuid_vec_t& textures); + void savedGLTFMaterials(const uuid_vec_t& materials); void saveTextureScaleRatios(LLRender::eTexIndex index_to_query); BOOL allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const; @@ -224,6 +225,7 @@ public: std::vector<LLColor4> mSavedColors; std::vector<LLColor4> mSavedShinyColors; uuid_vec_t mSavedTextures; + uuid_vec_t mSavedGLTFMaterials; std::vector<LLVector3> mTextureScaleRatios; std::vector<LLVector3> mSilhouetteVertices; // array of vertices to render silhouette of object std::vector<LLVector3> mSilhouetteNormals; // array of normals to render silhouette of object @@ -609,6 +611,7 @@ public: void selectionRevertColors(); void selectionRevertShinyColors(); BOOL selectionRevertTextures(); + void selectionRevertGLTFMaterials(); void selectionSetBumpmap( U8 bumpmap, const LLUUID &image_id ); void selectionSetTexGen( U8 texgen ); void selectionSetShiny( U8 shiny, const LLUUID &image_id ); diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 14a9f4aa30..a1c703b02f 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -758,6 +758,7 @@ LLSettingsSky::parammapping_t LLSettingsVOSky::getParameterMap() const param_map[SETTING_SKY_DROPLET_RADIUS] = DefaultParam(LLShaderMgr::DROPLET_RADIUS, sky_defaults[SETTING_SKY_DROPLET_RADIUS]); param_map[SETTING_SKY_ICE_LEVEL] = DefaultParam(LLShaderMgr::ICE_LEVEL, sky_defaults[SETTING_SKY_ICE_LEVEL]); + param_map[SETTING_REFLECTION_PROBE_AMBIANCE] = DefaultParam(LLShaderMgr::REFLECTION_PROBE_AMBIANCE, sky_defaults[SETTING_REFLECTION_PROBE_AMBIANCE]); // AdvancedAtmospherics TODO // Provide mappings for new shader params here } @@ -1026,12 +1027,39 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPreset(const std::string &n std::set<std::string> framenames; std::set<std::string> notfound; + // expected and correct folder sctructure is to have + // three folders in widnlight's root: days, water, skies std::string base_path(gDirUtilp->getDirName(path)); std::string water_path(base_path); std::string sky_path(base_path); + std::string day_path(base_path); gDirUtilp->append(water_path, "water"); gDirUtilp->append(sky_path, "skies"); + gDirUtilp->append(day_path, "days"); + + if (!gDirUtilp->fileExists(day_path)) + { + LL_WARNS("SETTINGS") << "File " << name << ".xml is not in \"days\" folder." << LL_ENDL; + } + + if (!gDirUtilp->fileExists(water_path)) + { + LL_WARNS("SETTINGS") << "Failed to find accompaniying water folder for file " << name + << ".xml. Falling back to using default folder" << LL_ENDL; + + water_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight"); + gDirUtilp->append(water_path, "water"); + } + + if (!gDirUtilp->fileExists(sky_path)) + { + LL_WARNS("SETTINGS") << "Failed to find accompaniying skies folder for file " << name + << ".xml. Falling back to using default folder" << LL_ENDL; + + sky_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight"); + gDirUtilp->append(sky_path, "skies"); + } newsettings[SETTING_NAME] = name; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 3ab7707df8..10b3683cc8 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -554,9 +554,12 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO sg_assert(mOctreeNode->getListenerCount() == 0); setState(SG_INITIAL_STATE_MASK); gPipeline.markRebuild(this, TRUE); + + // let the reflection map manager know about this spatial group + mReflectionProbe = gPipeline.mReflectionMapManager.registerSpatialGroup(this); - mRadius = 1; - mPixelArea = 1024.f; + mRadius = 1; + mPixelArea = 1024.f; } void LLSpatialGroup::updateDistance(LLCamera &camera) @@ -1399,7 +1402,9 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result return 0; } - + +extern BOOL gCubeSnapshot; + S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL; @@ -1418,7 +1423,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion) LLOctreeCullShadow culler(&camera); culler.traverse(mOctree); } - else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) + else if (mInfiniteFarClip || (!LLPipeline::sUseFarClip && !gCubeSnapshot)) { LLOctreeCullNoFarClip culler(&camera); culler.traverse(mOctree); @@ -1738,7 +1743,7 @@ void renderOctree(LLSpatialGroup* group) } }*/ } - + // LLSpatialGroup::OctreeNode* node = group->mOctreeNode; // gGL.diffuseColor4f(0,1,0,1); // drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize())); @@ -2610,14 +2615,12 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) gGL.diffuseColor4fv(line_color.mV); gGL.syncMatrices(); { - LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x20FF20 ) glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); } gGL.diffuseColor4fv(color.mV); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); { - LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x40FF40 ) glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); } } @@ -3156,7 +3159,6 @@ void renderRaycast(LLDrawable* drawablep) gGL.diffuseColor4f(0,1,1,0.5f); glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions); gGL.syncMatrices(); - LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x60FF60 ); glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); } @@ -3704,7 +3706,7 @@ void LLSpatialPartition::renderDebug() //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY | - LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) + LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) { return; } @@ -3738,7 +3740,6 @@ void LLSpatialPartition::renderDebug() LLOctreeRenderNonOccluded render_debug(camera); render_debug.traverse(mOctree); - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) { { @@ -3801,8 +3802,9 @@ public: LLDrawable* mHit; BOOL mPickTransparent; BOOL mPickRigged; + BOOL mPickUnselectable; - LLOctreeIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, BOOL pick_rigged, + LLOctreeIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_unselectable, S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) : mStart(start), mEnd(end), @@ -3813,7 +3815,8 @@ public: mTangent(tangent), mHit(NULL), mPickTransparent(pick_transparent), - mPickRigged(pick_rigged) + mPickRigged(pick_rigged), + mPickUnselectable(pick_unselectable) { } @@ -3898,7 +3901,7 @@ public: LLVOAvatar* avatar = (LLVOAvatar*) vobj; if ((mPickRigged) || ((avatar->isSelf()) && (LLFloater::isVisible(gFloaterTools)))) { - LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mPickRigged, mFaceHit, &intersection, mTexCoord, mNormal, mTangent); + LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mPickRigged, mPickUnselectable, mFaceHit, &intersection, mTexCoord, mNormal, mTangent); if (hit) { mEnd = intersection; @@ -3914,7 +3917,7 @@ public: } } - if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mPickRigged, mFaceHit, &intersection, mTexCoord, mNormal, mTangent)) + if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mPickRigged, mPickUnselectable, mFaceHit, &intersection, mTexCoord, mNormal, mTangent)) { mEnd = intersection; // shorten ray so we only find CLOSER hits if (mIntersection) @@ -3934,6 +3937,7 @@ public: LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, // return the face hit LLVector4a* intersection, // return the intersection point LLVector2* tex_coord, // return the texture coordinates of the intersection point @@ -3942,12 +3946,30 @@ LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector4a& start, co ) { - LLOctreeIntersect intersect(start, end, pick_transparent, pick_rigged, face_hit, intersection, tex_coord, normal, tangent); + LLOctreeIntersect intersect(start, end, pick_transparent, pick_rigged, pick_unselectable, face_hit, intersection, tex_coord, normal, tangent); LLDrawable* drawable = intersect.check(mOctree); return drawable; } +LLDrawable* LLSpatialGroup::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + BOOL pick_transparent, + BOOL pick_rigged, + BOOL pick_unselectable, + S32* face_hit, // return the face hit + LLVector4a* intersection, // return the intersection point + LLVector2* tex_coord, // return the texture coordinates of the intersection point + LLVector4a* normal, // return the surface normal at the intersection point + LLVector4a* tangent // return the surface tangent at the intersection point +) + +{ + LLOctreeIntersect intersect(start, end, pick_transparent, pick_rigged, pick_unselectable, face_hit, intersection, tex_coord, normal, tangent); + LLDrawable* drawable = intersect.check(getOctreeNode()); + + return drawable; +} + LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, LLViewerTexture* texture, LLVertexBuffer* buffer, bool selected, diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 6d3ef33801..c3e9d8ceb9 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -53,6 +53,7 @@ class LLSpatialPartition; class LLSpatialBridge; class LLSpatialGroup; class LLViewerRegion; +class LLReflectionMap; void pushVerts(LLFace* face, U32 mask); @@ -112,9 +113,14 @@ public: LL_ALIGN_16(LLFace* mFace); //associated face F32 mDistance; U32 mDrawMode; - LLMaterialPtr mMaterial; // If this is null, the following parameters are unused. - LLMaterialID mMaterialID; - U32 mShaderMask; + + // Material points here are likely for debugging only and are immaterial (zing!) + LLMaterialPtr mMaterial; + LLPointer<LLGLTFMaterial> mGLTFMaterial; + + LLUUID mMaterialID; // id of LLGLTFMaterial or LLMaterial applied to this draw info + + U32 mShaderMask; U32 mBlendFuncSrc; U32 mBlendFuncDst; BOOL mHasGlow; @@ -122,6 +128,8 @@ public: const LLMatrix4* mSpecularMapMatrix; LLPointer<LLViewerTexture> mNormalMap; const LLMatrix4* mNormalMapMatrix; + LLPointer<LLViewerTexture> mEmissiveMap; + LLVector4 mSpecColor; // XYZ = Specular RGB, W = Specular Exponent F32 mEnvIntensity; F32 mAlphaMaskCutoff; @@ -313,6 +321,18 @@ public: void drawObjectBox(LLColor4 col); + LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + BOOL pick_transparent, + BOOL pick_rigged, + BOOL pick_unselectable, + S32* face_hit, // return the face hit + LLVector4a* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point + ); + + LLSpatialPartition* getSpatialPartition() {return (LLSpatialPartition*)mSpatialPartition;} //LISTENER FUNCTIONS @@ -355,6 +375,9 @@ public: //used by LLVOAVatar to set render order in alpha draw pool to preserve legacy render order behavior LLVOAvatar* mAvatarp = nullptr; U32 mRenderOrder = 0; + // Reflection Probe associated with this node (if any) + LLPointer<LLReflectionMap> mReflectionProbe = nullptr; + } LL_ALIGN_POSTFIX(64); class LLGeometryManager @@ -382,6 +405,7 @@ public: LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, // return the face hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 98b2bc703b..0829b1a213 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1062,7 +1062,7 @@ bool idle_startup() { // Generic failure message std::ostringstream emsg; - emsg << LLTrans::getString("LoginFailed") << "\n"; + emsg << LLTrans::getString("LoginFailedHeader") << "\n"; if(LLLoginInstance::getInstance()->authFailure()) { LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " @@ -1075,11 +1075,37 @@ bool idle_startup() std::string message_id = response["message_id"]; std::string message; // actual string to show the user - if(!message_id.empty() && LLTrans::findString(message, message_id, response["message_args"])) - { - // message will be filled in with the template and arguments - } - else if(!message_response.empty()) + bool localized_by_id = false; + if(!message_id.empty()) + { + LLSD message_args = response["message_args"]; + if (message_args.has("TIME") + && (message_id == "LoginFailedAcountSuspended" + || message_id == "LoginFailedAccountMaintenance")) + { + LLDate date; + std::string time_string; + if (date.fromString(message_args["TIME"].asString())) + { + LLSD args; + args["datetime"] = (S32)date.secondsSinceEpoch(); + LLTrans::findString(time_string, "LocalTime", args); + } + else + { + time_string = message_args["TIME"].asString() + " " + LLTrans::getString("PacificTime"); + } + + message_args["TIME"] = time_string; + } + // message will be filled in with the template and arguments + if (LLTrans::findString(message, message_id, message_args)) + { + localized_by_id = true; + } + } + + if(!localized_by_id && !message_response.empty()) { // *HACK: "no_inventory_host" sent as the message itself. // Remove this clause when server is sending message_id as well. diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 1c4a56b549..2c7cb6a2c3 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -41,12 +41,15 @@ #include "llfolderviewmodel.h" #include "llinventory.h" #include "llinventoryfunctions.h" +#include "llinventoryicon.h" #include "llinventorymodelbackgroundfetch.h" #include "llinventoryobserver.h" #include "llinventorypanel.h" #include "lllineeditor.h" +#include "llmaterialeditor.h" #include "llui.h" #include "llviewerinventory.h" +#include "llviewermenufile.h" // LLFilePickerReplyThread #include "llpermissions.h" #include "llsaleinfo.h" #include "llassetstorage.h" @@ -69,16 +72,70 @@ #include "llradiogroup.h" #include "llfloaterreg.h" #include "lllocalbitmaps.h" +#include "lllocalgltfmaterials.h" #include "llerror.h" #include "llavatarappearancedefines.h" -static const S32 LOCAL_TRACKING_ID_COLUMN = 1; - -//static const char CURRENT_IMAGE_NAME[] = "Current Texture"; -//static const char WHITE_IMAGE_NAME[] = "Blank Texture"; -//static const char NO_IMAGE_NAME[] = "None"; +//static +bool get_is_predefined_texture(LLUUID asset_id) +{ + if (asset_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture")) + || asset_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID")) + || asset_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")) + || asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) + { + return true; + } + return false; +} + +LLUUID get_copy_free_item_by_asset_id(LLUUID asset_id, bool no_trans_perm) +{ + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(asset_id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + LLUUID res; + if (items.size()) + { + for (S32 i = 0; i < items.size(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp) + { + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + bool allow_trans = item_permissions.allowOperationBy(PERM_TRANSFER, gAgent.getID(), gAgent.getGroupID()); + if (allow_trans != no_trans_perm) + { + return itemp->getUUID(); + } + res = itemp->getUUID(); + } + } + } + } + return res; +} + +bool get_can_copy_texture(LLUUID asset_id) +{ + // User is allowed to copy a texture if: + // library asset or default texture, + // or copy perm asset exists in user's inventory + + return get_is_predefined_texture(asset_id) || get_copy_free_item_by_asset_id(asset_id).notNull(); +} LLFloaterTexturePicker::LLFloaterTexturePicker( LLView* owner, @@ -121,8 +178,8 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( mOnUpdateImageStatsCallback(NULL), mBakeTextureEnabled(FALSE) { - buildFromFile("floater_texture_ctrl.xml"); mCanApplyImmediately = can_apply_immediately; + buildFromFile("floater_texture_ctrl.xml"); setCanMinimize(FALSE); } @@ -193,10 +250,8 @@ void LLFloaterTexturePicker::setActive( BOOL active ) void LLFloaterTexturePicker::setCanApplyImmediately(BOOL b) { mCanApplyImmediately = b; - if (!mCanApplyImmediately) - { - getChild<LLUICtrl>("apply_immediate_check")->setValue(FALSE); - } + + getChild<LLUICtrl>("apply_immediate_check")->setValue(mCanApplyImmediately); updateFilterPermMask(); } @@ -358,23 +413,29 @@ BOOL LLFloaterTexturePicker::postBuild() childSetCommitCallback("show_folders_check", onShowFolders, this); getChildView("show_folders_check")->setVisible( FALSE); - mFilterEdit = getChild<LLFilterEditor>("inventory search editor"); - mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2)); + mFilterEdit = getChild<LLFilterEditor>("inventory search editor"); + mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2)); mInventoryPanel = getChild<LLInventoryPanel>("inventory panel"); + mTextureMaterialsCombo = getChild<LLComboBox>("textures_material_combo"); + mTextureMaterialsCombo->setCommitCallback(onSelectTextureMaterials, this); + + // set the combo box to the first entry in the list (currently textures and materials) + mTextureMaterialsCombo->selectByValue(0); + mModeSelector = getChild<LLComboBox>("mode_selection"); mModeSelector->setCommitCallback(onModeSelect, this); mModeSelector->selectByValue(0); if(mInventoryPanel) { - U32 filter_types = 0x0; - filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; - filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; + // to avoid having to make an assumption about which option is + // selected at startup, we call the same function that is triggered + // when a texture/materials/both choice is made and let it take care + // of setting the filters + onSelectTextureMaterials(0, this); - mInventoryPanel->setFilterTypes(filter_types); - //mInventoryPanel->setFilterPermMask(getFilterPermMask()); //Commented out due to no-copy texture loss. mInventoryPanel->setFilterPermMask(mImmediateFilterPermMask); mInventoryPanel->setSelectCallback(boost::bind(&LLFloaterTexturePicker::onSelectionChange, this, _1, _2)); mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); @@ -407,17 +468,15 @@ BOOL LLFloaterTexturePicker::postBuild() mLocalScrollCtrl = getChild<LLScrollListCtrl>("l_name_list"); mLocalScrollCtrl->setCommitCallback(onLocalScrollCommit, this); + mLocalScrollCtrl->clearRows(); LLLocalBitmapMgr::getInstance()->feedScrollList(mLocalScrollCtrl); + LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(mLocalScrollCtrl); mNoCopyTextureSelected = FALSE; getChild<LLUICtrl>("apply_immediate_check")->setValue(gSavedSettings.getBOOL("TextureLivePreview")); childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this); - - if (!mCanApplyImmediately) - { - getChildView("show_folders_check")->setEnabled(FALSE); - } + getChildView("apply_immediate_check")->setEnabled(mCanApplyImmediately); getChild<LLUICtrl>("Pipette")->setCommitCallback( boost::bind(&LLFloaterTexturePicker::onBtnPipette, this)); childSetAction("Cancel", LLFloaterTexturePicker::onBtnCancel,this); @@ -483,7 +542,7 @@ void LLFloaterTexturePicker::draw() } getChildView("Default")->setEnabled(mImageAssetID != mDefaultImageAssetID || mTentative); - getChildView("Blank")->setEnabled(mImageAssetID != mBlankImageAssetID || mTentative); + getChildView("Blank")->setEnabled((mImageAssetID != mBlankImageAssetID && mBlankImageAssetID != mDefaultImageAssetID) || mTentative); getChildView("None")->setEnabled(mAllowNoTexture && (!mImageAssetID.isNull() || mTentative)); LLFloater::draw(); @@ -688,8 +747,18 @@ void LLFloaterTexturePicker::onBtnSelect(void* userdata) { if (self->mLocalScrollCtrl->getVisible() && !self->mLocalScrollCtrl->getAllSelected().empty()) { - LLUUID temp_id = self->mLocalScrollCtrl->getFirstSelected()->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID(); - local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id); + LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue(); + LLUUID temp_id = data["id"]; + S32 asset_type = data["type"].asInteger(); + + if (LLAssetType::AT_MATERIAL == asset_type) + { + local_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(temp_id); + } + else + { + local_id = LLLocalBitmapMgr::getInstance()->getWorldID(temp_id); + } } } @@ -762,6 +831,7 @@ void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata) self->getChild<LLButton>("Blank")->setVisible(index == 0 ? TRUE : FALSE); self->getChild<LLButton>("None")->setVisible(index == 0 ? TRUE : FALSE); self->getChild<LLButton>("Pipette")->setVisible(index == 0 ? TRUE : FALSE); + self->getChild<LLComboBox>("textures_material_combo")->setVisible(index == 0 ? TRUE : FALSE); self->getChild<LLFilterEditor>("inventory search editor")->setVisible(index == 0 ? TRUE : FALSE); self->getChild<LLInventoryPanel>("inventory panel")->setVisible(index == 0 ? TRUE : FALSE); @@ -836,11 +906,13 @@ void LLFloaterTexturePicker::onModeSelect(LLUICtrl* ctrl, void *userdata) // static void LLFloaterTexturePicker::onBtnAdd(void* userdata) { - if (LLLocalBitmapMgr::getInstance()->addUnit() == true) - { - LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; - LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); - } + LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)userdata; + + // todo: there will be changes to texture picker to forbid + // selection of materials in some cases, like landmarks, once + // it gets implemented, update code to select FLOAD_* filter + // based on picker's material/texture mode. + LLFilePickerReplyThread::startPicker(boost::bind(&onPickerCallback, _1, self->getHandle()), LLFilePicker::FFLOAD_MATERIAL_TEXTURE, true); } // static @@ -851,22 +923,34 @@ void LLFloaterTexturePicker::onBtnRemove(void* userdata) if (!selected_items.empty()) { + for(std::vector<LLScrollListItem*>::iterator iter = selected_items.begin(); iter != selected_items.end(); iter++) { LLScrollListItem* list_item = *iter; if (list_item) { - LLUUID tracking_id = list_item->getColumn(LOCAL_TRACKING_ID_COLUMN)->getValue().asUUID(); - LLLocalBitmapMgr::getInstance()->delUnit(tracking_id); + LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue(); + LLUUID tracking_id = data["id"]; + S32 asset_type = data["type"].asInteger(); + + if (LLAssetType::AT_MATERIAL == asset_type) + { + LLLocalGLTFMaterialMgr::getInstance()->delUnit(tracking_id); + } + else + { + LLLocalBitmapMgr::getInstance()->delUnit(tracking_id); + } } } self->getChild<LLButton>("l_rem_btn")->setEnabled(false); self->getChild<LLButton>("l_upl_btn")->setEnabled(false); + self->mLocalScrollCtrl->clearRows(); LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); + LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); } - } // static @@ -882,15 +966,31 @@ void LLFloaterTexturePicker::onBtnUpload(void* userdata) /* currently only allows uploading one by one, picks the first item from the selection list. (not the vector!) in the future, it might be a good idea to check the vector size and if more than one units is selected - opt for multi-image upload. */ - - LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN); - std::string filename = LLLocalBitmapMgr::getInstance()->getFilename(tracking_id); - - if (!filename.empty()) - { - LLFloaterReg::showInstance("upload_image", LLSD(filename)); - } + LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue(); + LLUUID tracking_id = data["id"]; + S32 asset_type = data["type"].asInteger(); + + if (LLAssetType::AT_MATERIAL == asset_type) + { + std::string filename = LLLocalGLTFMaterialMgr::getInstance()->getFilename(tracking_id); + if (!filename.empty()) + { + LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::getInstance("material_editor"); + if (me) + { + me->loadMaterialFromFile(filename); + } + } + } + else + { + std::string filename = LLLocalBitmapMgr::getInstance()->getFilename(tracking_id); + if (!filename.empty()) + { + LLFloaterReg::showInstance("upload_image", LLSD(filename)); + } + } } //static @@ -906,8 +1006,20 @@ void LLFloaterTexturePicker::onLocalScrollCommit(LLUICtrl* ctrl, void* userdata) if (has_selection) { - LLUUID tracking_id = (LLUUID)self->mLocalScrollCtrl->getSelectedItemLabel(LOCAL_TRACKING_ID_COLUMN); - LLUUID inworld_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id); + LLSD data = self->mLocalScrollCtrl->getFirstSelected()->getValue(); + LLUUID tracking_id = data["id"]; + S32 asset_type = data["type"].asInteger(); + LLUUID inworld_id; + + if (LLAssetType::AT_MATERIAL == asset_type) + { + inworld_id = LLLocalGLTFMaterialMgr::getInstance()->getWorldID(tracking_id); + } + else + { + inworld_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id); + } + if (self->mSetImageAssetIDCallback) { self->mSetImageAssetIDCallback(inworld_id); @@ -1081,6 +1193,38 @@ void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string ) mInventoryPanel->setFilterSubString(search_string); } +void LLFloaterTexturePicker::onSelectTextureMaterials(LLUICtrl* ctrl, void *userdata) +{ + LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)userdata; + int index = self->mTextureMaterialsCombo->getValue().asInteger(); + + // IMPORTANT: make sure these match the entries in floater_texture_ctrl.xml + // for the textures_material_combo combo box + const int textures_and_materials = 0; + const int textures_only = 1; + const int materials_only = 2; + + U32 filter_types = 0x0; + + if (index == textures_and_materials) + { + filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; + filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; + filter_types |= 0x1 << LLInventoryType::IT_MATERIAL; + } + else if (index == textures_only) + { + filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; + filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; + } + else if (index == materials_only) + { + filter_types |= 0x1 << LLInventoryType::IT_MATERIAL; + } + + self->mInventoryPanel->setFilterTypes(filter_types); +} + void LLFloaterTexturePicker::setLocalTextureEnabled(BOOL enabled) { mModeSelector->setEnabledByValue(1, enabled); @@ -1108,6 +1252,36 @@ void LLFloaterTexturePicker::setBakeTextureEnabled(BOOL enabled) onModeSelect(0, this); } +void LLFloaterTexturePicker::onPickerCallback(const std::vector<std::string>& filenames, LLHandle<LLFloater> handle) +{ + std::vector<std::string>::const_iterator iter = filenames.begin(); + while (iter != filenames.end()) + { + if (!iter->empty()) + { + std::string temp_exten = gDirUtilp->getExtension(*iter); + if (temp_exten == "gltf" || temp_exten == "glb") + { + LLLocalGLTFMaterialMgr::getInstance()->addUnit(*iter); + } + else + { + LLLocalBitmapMgr::getInstance()->addUnit(*iter); + } + } + iter++; + } + + // Todo: this should referesh all pickers, not just a current one + if (!handle.isDead()) + { + LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)handle.get(); + self->mLocalScrollCtrl->clearRows(); + LLLocalBitmapMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); + LLLocalGLTFMaterialMgr::getInstance()->feedScrollList(self->mLocalScrollCtrl); + } +} + void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te ) { LLUUID inventory_item_id = findItemID(te.getID(), TRUE); @@ -1146,7 +1320,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) mOnCloseCallback(NULL), mOnSelectCallback(NULL), mBorderColor( p.border_color() ), - mAllowNoTexture( FALSE ), + mAllowNoTexture( p.allow_no_texture ), mAllowLocalTexture( TRUE ), mImmediateFilterPermMask( PERM_NONE ), mNonImmediateFilterPermMask( PERM_NONE ), @@ -1439,9 +1613,9 @@ void LLTextureCtrl::onFloaterClose() void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id) { - LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get(); + LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get(); - if( floaterp && getEnabled()) + if( floaterp && getEnabled()) { if (op == TEXTURE_CANCEL) mViewModel->resetDirty(); @@ -1462,15 +1636,64 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id) } else { - mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE); - LL_DEBUGS() << "mImageItemID: " << mImageItemID << LL_ENDL; - mImageAssetID = floaterp->getAssetID(); - LL_DEBUGS() << "mImageAssetID: " << mImageAssetID << LL_ENDL; + mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE); + LL_DEBUGS() << "mImageItemID: " << mImageItemID << LL_ENDL; + mImageAssetID = floaterp->getAssetID(); + LL_DEBUGS() << "mImageAssetID: " << mImageAssetID << LL_ENDL; } if (op == TEXTURE_SELECT && mOnSelectCallback) { - mOnSelectCallback( this, LLSD() ); + // determine if the selected item in inventory is a material + // by finding the item in inventory and inspecting its (IT_) type + LLUUID item_id = floaterp->findItemID(floaterp->getAssetID(), FALSE); + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) + { + if (item->getInventoryType() == LLInventoryType::IT_MATERIAL) + { + // ask the selection manager for the list of selected objects + // to which the material will be applied. + LLObjectSelectionHandle selectedObjectsHandle = LLSelectMgr::getInstance()->getSelection(); + if (selectedObjectsHandle.notNull()) + { + LLObjectSelection* selectedObjects = selectedObjectsHandle.get(); + if (!selectedObjects->isEmpty()) + { + // we have a selection - iterate over it + for (LLObjectSelection::valid_iterator obj_iter = selectedObjects->valid_begin(); + obj_iter != selectedObjects->valid_end(); + ++obj_iter) + { + LLSelectNode* object = *obj_iter; + LLViewerObject* viewer_object = object->getObject(); + if (viewer_object) + { + // the asset ID of the material we want to apply + // the the selected objects + LLUUID asset_id = item->getAssetUUID(); + + // iterate over the faces in the object + // TODO: consider the case where user has + // selected only certain faces + S32 num_faces = viewer_object->getNumTEs(); + for (S32 face = 0; face < num_faces; face++) + { + viewer_object->setRenderMaterialID(face, asset_id); + dialog_refresh_all(); + } + viewer_object->sendTEUpdate(); + } + } + } + } + } + } + else + // original behavior for textures, not materials + { + mOnSelectCallback(this, LLSD()); + } } else if (op == TEXTURE_CANCEL && mOnCancelCallback) { @@ -1481,8 +1704,10 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id) // If the "no_commit_on_selection" parameter is set // we commit only when user presses OK in the picker // (i.e. op == TEXTURE_SELECT) or texture changes via DnD. - if (mCommitOnSelection || op == TEXTURE_SELECT) - onCommit(); + if (mCommitOnSelection || op == TEXTURE_SELECT) + { + onCommit(); + } } } } @@ -1615,7 +1840,7 @@ void LLTextureCtrl::draw() } else//mImageAssetID == LLUUID::null { - mTexturep = NULL; + mTexturep = NULL; } // Border diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 92f6f89af6..b77ff98d80 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -52,6 +52,16 @@ class LLViewerFetchedTexture; typedef boost::function<BOOL (LLUICtrl*, LLInventoryItem*)> drag_n_drop_callback; typedef boost::function<void (LLInventoryItem*)> texture_selected_callback; +// Helper functions for UI that work with picker +bool get_is_predefined_texture(LLUUID asset_id); + +// texture picker works by asset ids since objects normaly do +// not retain inventory ids as result these functions are looking +// for textures in inventory by asset ids +// This search can be performance unfriendly and doesn't warranty +// that the texture is original source of asset +LLUUID get_copy_free_item_by_asset_id(LLUUID image_id, bool no_trans_perm = false); +bool get_can_copy_texture(LLUUID image_id); ////////////////////////////////////////////////////////////////////////////////////////// // LLTextureCtrl @@ -91,7 +101,7 @@ public: : image_id("image"), default_image_id("default_image_id"), default_image_name("default_image_name"), - allow_no_texture("allow_no_texture"), + allow_no_texture("allow_no_texture", false), can_apply_immediately("can_apply_immediately"), no_commit_on_selection("no_commit_on_selection", false), label_width("label_width", -1), @@ -330,9 +340,13 @@ public: static void onBakeTextureSelect(LLUICtrl* ctrl, void *userdata); static void onHideBaseMeshRegionCheck(LLUICtrl* ctrl, void *userdata); + static void onSelectTextureMaterials(LLUICtrl* ctrl, void *userdata); + void setLocalTextureEnabled(BOOL enabled); void setBakeTextureEnabled(BOOL enabled); + static void onPickerCallback(const std::vector<std::string>& filenames, LLHandle<LLFloater> handle); + protected: LLPointer<LLViewerTexture> mTexturep; LLView* mOwner; @@ -355,6 +369,7 @@ protected: BOOL mActive; LLFilterEditor* mFilterEdit; + LLComboBox* mTextureMaterialsCombo; LLInventoryPanel* mInventoryPanel; PermissionMask mImmediateFilterPermMask; PermissionMask mDnDFilterPermMask; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 544b0e6802..dc10e42446 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -3324,6 +3324,7 @@ void LLTextureFetch::sendRequestListToSimulators() gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); } S32 packet = req->mLastPacket + 1; + LL_INFOS() << req->mID << ": " << req->mImagePriority << LL_ENDL; gMessageSystem->nextBlockFast(_PREHASH_RequestImage); gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID); gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)req->mDesiredDiscard); diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp new file mode 100644 index 0000000000..935f8e7794 --- /dev/null +++ b/indra/newview/lltinygltfhelper.cpp @@ -0,0 +1,245 @@ +/** + * @file lltinygltfhelper.cpp + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 "llviewerprecompiledheaders.h" + +#include "lltinygltfhelper.h" + +#include "llimage.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" + +void strip_alpha_channel(LLPointer<LLImageRaw>& img) +{ + if (img->getComponents() == 4) + { + LLImageRaw* tmp = new LLImageRaw(img->getWidth(), img->getHeight(), 3); + tmp->copyUnscaled4onto3(img); + img = tmp; + } +} + +// copy red channel from src_img to dst_img +// PRECONDITIONS: +// dst_img must be 3 component +// src_img and dst_image must have the same dimensions +void copy_red_channel(LLPointer<LLImageRaw>& src_img, LLPointer<LLImageRaw>& dst_img) +{ + llassert(src_img->getWidth() == dst_img->getWidth() && src_img->getHeight() == dst_img->getHeight()); + llassert(dst_img->getComponents() == 3); + + U32 pixel_count = dst_img->getWidth() * dst_img->getHeight(); + U8* src = src_img->getData(); + U8* dst = dst_img->getData(); + S8 src_components = src_img->getComponents(); + + for (U32 i = 0; i < pixel_count; ++i) + { + dst[i * 3] = src[i * src_components]; + } +} + +void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material, + LLPointer<LLImageRaw>& albedo_img, + LLPointer<LLImageRaw>& normal_img, + LLPointer<LLImageRaw>& mr_img, + LLPointer<LLImageRaw>& emissive_img, + LLPointer<LLImageRaw>& occlusion_img, + LLPointer<LLViewerFetchedTexture>& albedo_tex, + LLPointer<LLViewerFetchedTexture>& normal_tex, + LLPointer<LLViewerFetchedTexture>& mr_tex, + LLPointer<LLViewerFetchedTexture>& emissive_tex) +{ + if (albedo_img) + { + albedo_tex = LLViewerTextureManager::getFetchedTexture(albedo_img, FTType::FTT_LOCAL_FILE, true); + } + + if (normal_img) + { + strip_alpha_channel(normal_img); + normal_tex = LLViewerTextureManager::getFetchedTexture(normal_img, FTType::FTT_LOCAL_FILE, true); + } + + if (mr_img) + { + strip_alpha_channel(mr_img); + + if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index) + { + // occlusion is a distinct texture from pbrMetallicRoughness + // pack into mr red channel + int occlusion_idx = material.occlusionTexture.index; + int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index; + if (occlusion_idx != mr_idx) + { + //scale occlusion image to match resolution of mr image + occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); + + copy_red_channel(occlusion_img, mr_img); + } + } + } + else if (occlusion_img) + { + //no mr but occlusion exists, make a white mr_img and copy occlusion red channel over + mr_img = new LLImageRaw(occlusion_img->getWidth(), occlusion_img->getHeight(), 3); + mr_img->clear(255, 255, 255); + copy_red_channel(occlusion_img, mr_img); + } + + if (mr_img) + { + mr_tex = LLViewerTextureManager::getFetchedTexture(mr_img, FTType::FTT_LOCAL_FILE, true); + } + + if (emissive_img) + { + strip_alpha_channel(emissive_img); + emissive_tex = LLViewerTextureManager::getFetchedTexture(emissive_img, FTType::FTT_LOCAL_FILE, true); + } +} + +void LLTinyGLTFHelper::setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model) +{ + S32 index; + + auto& material_in = model.materials[0]; + + // get albedo texture + index = material_in.pbrMetallicRoughness.baseColorTexture.index; + if (index >= 0) + { + mat->mAlbedoId.set(model.images[index].uri); + } + else + { + mat->mAlbedoId.setNull(); + } + + // get normal map + index = material_in.normalTexture.index; + if (index >= 0) + { + mat->mNormalId.set(model.images[index].uri); + } + else + { + mat->mNormalId.setNull(); + } + + // get metallic-roughness texture + index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index; + if (index >= 0) + { + mat->mMetallicRoughnessId.set(model.images[index].uri); + } + else + { + mat->mMetallicRoughnessId.setNull(); + } + + // get emissive texture + index = material_in.emissiveTexture.index; + if (index >= 0) + { + mat->mEmissiveId.set(model.images[index].uri); + } + else + { + mat->mEmissiveId.setNull(); + } + + mat->setAlphaMode(material_in.alphaMode); + mat->mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f); + + mat->mAlbedoColor = getColor(material_in.pbrMetallicRoughness.baseColorFactor); + mat->mEmissiveColor = getColor(material_in.emissiveFactor); + + mat->mMetallicFactor = llclamp((F32)material_in.pbrMetallicRoughness.metallicFactor, 0.f, 1.f); + mat->mRoughnessFactor = llclamp((F32)material_in.pbrMetallicRoughness.roughnessFactor, 0.f, 1.f); + + mat->mDoubleSided = material_in.doubleSided; +} + +LLColor4 LLTinyGLTFHelper::getColor(const std::vector<double>& in) +{ + LLColor4 out; + for (S32 i = 0; i < llmin((S32)in.size(), 4); ++i) + { + out.mV[i] = in[i]; + } + + return out; +} + +const tinygltf::Image * LLTinyGLTFHelper::getImageFromTextureIndex(const tinygltf::Model & model, S32 texture_index) +{ + if (texture_index >= 0) + { + S32 source_idx = model.textures[texture_index].source; + if (source_idx >= 0) + { + return &(model.images[source_idx]); + } + } + + return nullptr; +} + +LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index, std::string & name) +{ + const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index); + LLImageRaw* rawImage = nullptr; + + if (image != nullptr && + image->bits == 8 && + !image->image.empty() && + image->component <= 4) + { + name = image->name; + rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component); + rawImage->verticalFlip(); + } + + return rawImage; +} + +LLImageRaw * LLTinyGLTFHelper::getTexture(const std::string & folder, const tinygltf::Model & model, S32 texture_index) +{ + const tinygltf::Image* image = getImageFromTextureIndex(model, texture_index); + LLImageRaw* rawImage = nullptr; + + if (image != nullptr && + image->bits == 8 && + !image->image.empty() && + image->component <= 4) + { + rawImage = new LLImageRaw(&image->image[0], image->width, image->height, image->component); + rawImage->verticalFlip(); + } + + return rawImage; +} diff --git a/indra/newview/lltinygltfhelper.h b/indra/newview/lltinygltfhelper.h new file mode 100644 index 0000000000..a25fdac41d --- /dev/null +++ b/indra/newview/lltinygltfhelper.h @@ -0,0 +1,55 @@ +/** + * @file lltinygltfhelper.h + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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 + +#include "llgltfmaterial.h" +#include "llpointer.h" +#include "tinygltf/tiny_gltf.h" + +class LLImageRaw; +class LLViewerFetchedTexture; + +namespace LLTinyGLTFHelper +{ + void setFromModel(LLGLTFMaterial* mat, tinygltf::Model& model); + LLColor4 getColor(const std::vector<double>& in); + const tinygltf::Image* getImageFromTextureIndex(const tinygltf::Model& model, S32 texture_index); + LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, std::string& name); + LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index); + + void initFetchedTextures(tinygltf::Material& material, + LLPointer<LLImageRaw>& albedo_img, + LLPointer<LLImageRaw>& normal_img, + LLPointer<LLImageRaw>& mr_img, + LLPointer<LLImageRaw>& emissive_img, + LLPointer<LLImageRaw>& occlusion_img, + LLPointer<LLViewerFetchedTexture>& albedo_tex, + LLPointer<LLViewerFetchedTexture>& normal_tex, + LLPointer<LLViewerFetchedTexture>& mr_tex, + LLPointer<LLViewerFetchedTexture>& emissive_tex); +} + diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index 8baad30e8f..692e8d91a9 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -291,7 +291,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal mLineEditor->setText(edit_text_contents); std::string notif_name = mNotification->getName(); - if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name)) + if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name) || ("CreateSubfolder" == notif_name)) { mLineEditor->setPrevalidate(&LLTextValidate::validateASCII); } diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 50868d0fa5..ab54e2afc6 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -256,7 +256,8 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() // |-------------------------------|----------------------------------------------|-----------------------------------------------|---------------------------------------------------|--------------------------------| addEntry(DAD_NONE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_TEXTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dTextureObject, &LLToolDragAndDrop::dad3dNULL)); - addEntry(DAD_SOUND, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); + addEntry(DAD_MATERIAL, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dMaterialObject, &LLToolDragAndDrop::dad3dNULL)); + addEntry(DAD_SOUND, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_CALLINGCARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_LANDMARK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_SCRIPT, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dRezScript, &LLToolDragAndDrop::dad3dNULL)); @@ -271,6 +272,7 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_MESH, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dMeshObject, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_SETTINGS, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); + // TODO: animation on self could play it? edit it? // TODO: gesture on self could play it? edit it? }; @@ -1062,6 +1064,64 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj, hit_obj->sendTEUpdate(); } + +void LLToolDragAndDrop::dropMaterialOneFace(LLViewerObject* hit_obj, + S32 hit_face, + LLInventoryItem* item, + LLToolDragAndDrop::ESource source, + const LLUUID& src_id) +{ + if (hit_face == -1) return; + if (!item || item->getInventoryType() != LLInventoryType::IT_MATERIAL) + { + LL_WARNS() << "LLToolDragAndDrop::dropTextureOneFace no material item." << LL_ENDL; + return; + } + LLUUID asset_id = item->getAssetUUID(); + BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id); + if (!success) + { + return; + } + + hit_obj->setRenderMaterialID(hit_face, asset_id); + + dialog_refresh_all(); + + // send the update to the simulator + hit_obj->sendTEUpdate(); +} + + +void LLToolDragAndDrop::dropMaterialAllFaces(LLViewerObject* hit_obj, + LLInventoryItem* item, + LLToolDragAndDrop::ESource source, + const LLUUID& src_id) +{ + if (!item || item->getInventoryType() != LLInventoryType::IT_MATERIAL) + { + LL_WARNS() << "LLToolDragAndDrop::dropTextureAllFaces no material item." << LL_ENDL; + return; + } + LLUUID asset_id = item->getAssetUUID(); + BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id); + if (!success) + { + return; + } + + S32 num_faces = hit_obj->getNumTEs(); + for (S32 face = 0; face < num_faces; face++) + { + // update viewer side material in anticipation of update from simulator + hit_obj->setRenderMaterialID(face, asset_id); + dialog_refresh_all(); + } + // send the update to the simulator + hit_obj->sendTEUpdate(); +} + + void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj, LLInventoryItem* item, LLToolDragAndDrop::ESource source, @@ -1100,7 +1160,8 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, S32 hit_face, LLInventoryItem* item, LLToolDragAndDrop::ESource source, - const LLUUID& src_id) + const LLUUID& src_id, + S32 tex_channel) { if (hit_face == -1) return; if (!item) @@ -1124,7 +1185,8 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, if (gFloaterTools->getVisible() && panel_face) { - switch (LLSelectMgr::getInstance()->getTextureChannel()) + tex_channel = (tex_channel > -1) ? tex_channel : LLSelectMgr::getInstance()->getTextureChannel(); + switch (tex_channel) { case 0: @@ -1628,6 +1690,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ case DAD_MESH: case DAD_CATEGORY: case DAD_SETTINGS: + case DAD_MATERIAL: { LLInventoryObject* inv_obj = (LLInventoryObject*)cargo_data; if(gInventory.getCategory(inv_obj->getUUID()) || (gInventory.getItem(inv_obj->getUUID()) @@ -1982,6 +2045,17 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( dropTextureOneFace(obj, face, item, mSource, mSourceID); } } + else if (cargo_type == DAD_MATERIAL) + { + if ((mask & MASK_SHIFT)) + { + dropMaterialAllFaces(obj, item, mSource, mSourceID); + } + else + { + dropMaterialOneFace(obj, face, item, mSource, mSourceID); + } + } else if (cargo_type == DAD_MESH) { dropMesh(obj, item, mSource, mSourceID); @@ -2010,6 +2084,12 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject( return dad3dApplyToObject(obj, face, mask, drop, DAD_TEXTURE); } +EAcceptance LLToolDragAndDrop::dad3dMaterialObject( + LLViewerObject* obj, S32 face, MASK mask, BOOL drop) +{ + return dad3dApplyToObject(obj, face, mask, drop, DAD_MATERIAL); +} + EAcceptance LLToolDragAndDrop::dad3dMeshObject( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 24a712029c..cfdbd931ce 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -168,6 +168,8 @@ protected: MASK mask, BOOL drop); EAcceptance dad3dTextureObject(LLViewerObject* obj, S32 face, MASK mask, BOOL drop); + EAcceptance dad3dMaterialObject(LLViewerObject* obj, S32 face, + MASK mask, BOOL drop); EAcceptance dad3dMeshObject(LLViewerObject* obj, S32 face, MASK mask, BOOL drop); // EAcceptance dad3dTextureSelf(LLViewerObject* obj, S32 face, @@ -244,11 +246,20 @@ public: static void dropTextureOneFace(LLViewerObject* hit_obj, S32 hit_face, LLInventoryItem* item, ESource source, - const LLUUID& src_id); + const LLUUID& src_id, + S32 tex_channel = -1); static void dropTextureAllFaces(LLViewerObject* hit_obj, LLInventoryItem* item, ESource source, const LLUUID& src_id); + static void dropMaterialOneFace(LLViewerObject* hit_obj, S32 hit_face, + LLInventoryItem* item, + ESource source, + const LLUUID& src_id); + static void dropMaterialAllFaces(LLViewerObject* hit_obj, + LLInventoryItem* item, + ESource source, + const LLUUID& src_id); static void dropMesh(LLViewerObject* hit_obj, LLInventoryItem* item, ESource source, diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index e52bc0b015..c6f3905ddc 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -65,7 +65,8 @@ BOOL LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask) { // do immediate pick query BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); - mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged); + BOOL pick_transparent = gSavedSettings.getBOOL("SelectInvisibleObjects"); + mPick = gViewerWindow->pickImmediate(x, y, pick_transparent, pick_rigged); // Pass mousedown to agent LLTool::handleMouseDown(x, y, mask); @@ -84,13 +85,13 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi } BOOL select_owned = gSavedSettings.getBOOL("SelectOwnedOnly"); BOOL select_movable = gSavedSettings.getBOOL("SelectMovableOnly"); - - // *NOTE: These settings must be cleaned up at bottom of function. + + // *NOTE: These settings must be cleaned up at bottom of function. if (temp_select || LLSelectMgr::getInstance()->mAllowSelectAvatar) { gSavedSettings.setBOOL("SelectOwnedOnly", FALSE); gSavedSettings.setBOOL("SelectMovableOnly", FALSE); - LLSelectMgr::getInstance()->setForceSelection(TRUE); + LLSelectMgr::getInstance()->setForceSelection(TRUE); } BOOL extend_select = (pick.mKeyMask == MASK_SHIFT) || (pick.mKeyMask == MASK_CONTROL); diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp index 4804ef6ddc..481086f760 100644 --- a/indra/newview/llviewerassettype.cpp +++ b/indra/newview/llviewerassettype.cpp @@ -88,6 +88,7 @@ LLViewerAssetDictionary::LLViewerAssetDictionary() addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE)); addEntry(LLViewerAssetType::AT_SETTINGS, new ViewerAssetEntry(DAD_SETTINGS)); + addEntry(LLViewerAssetType::AT_MATERIAL, new ViewerAssetEntry(DAD_MATERIAL)); }; EDragAndDropType LLViewerAssetType::lookupDragAndDropType(EType asset_type) diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 3f7e8531fb..8e1ebdf6fa 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -497,6 +497,67 @@ LLSD LLNewFileResourceUploadInfo::exportTempFile() } //========================================================================= +LLNewBufferedResourceUploadInfo::LLNewBufferedResourceUploadInfo( + const std::string& buffer, + const LLAssetID& asset_id, + std::string name, + std::string description, + S32 compressionInfo, + LLFolderType::EType destinationType, + LLInventoryType::EType inventoryType, + LLAssetType::EType assetType, + U32 nextOWnerPerms, + U32 groupPerms, + U32 everyonePerms, + S32 expectedCost, + bool show_inventory, + uploadFinish_f finish) + : LLResourceUploadInfo(name, description, compressionInfo, + destinationType, inventoryType, + nextOWnerPerms, groupPerms, everyonePerms, expectedCost, show_inventory) + , mBuffer(buffer) + , mFinishFn(finish) +{ + setAssetType(assetType); + setAssetId(asset_id); +} + +LLSD LLNewBufferedResourceUploadInfo::prepareUpload() +{ + if (getAssetId().isNull()) + generateNewAssetId(); + + LLSD result = exportTempFile(); + if (result.has("error")) + return result; + + return LLResourceUploadInfo::prepareUpload(); +} + +LLSD LLNewBufferedResourceUploadInfo::exportTempFile() +{ + std::string filename = gDirUtilp->getTempFilename(); + + // copy buffer to the cache for upload + LLFileSystem file(getAssetId(), getAssetType(), LLFileSystem::APPEND); + file.write((U8*) mBuffer.c_str(), mBuffer.size()); + + return LLSD(); +} + +LLUUID LLNewBufferedResourceUploadInfo::finishUpload(LLSD &result) +{ + LLUUID newItemId = LLResourceUploadInfo::finishUpload(result); + + if (mFinishFn) + { + mFinishFn(result["new_asset"].asUUID(), result); + } + + return newItemId; +} + +//========================================================================= LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish) : LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, 0, 0, 0, 0), diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h index e56ba7d8f7..9eddcfbd0e 100644 --- a/indra/newview/llviewerassetupload.h +++ b/indra/newview/llviewerassetupload.h @@ -168,6 +168,41 @@ private: }; //------------------------------------------------------------------------- +// use when you have a resource in memory and you want to make a new inventory item +class LLNewBufferedResourceUploadInfo : public LLResourceUploadInfo +{ +public: + typedef std::function<void(LLUUID newAssetId, LLSD response)> uploadFinish_f; + + LLNewBufferedResourceUploadInfo( + const std::string& buffer, + const LLAssetID& asset_id, + std::string name, + std::string description, + S32 compressionInfo, + LLFolderType::EType destinationType, + LLInventoryType::EType inventoryType, + LLAssetType::EType assetType, + U32 nextOWnerPerms, + U32 groupPerms, + U32 everyonePerms, + S32 expectedCost, + bool show_inventory, + uploadFinish_f finish); + + virtual LLSD prepareUpload(); + +protected: + + virtual LLSD exportTempFile(); + virtual LLUUID finishUpload(LLSD &result); + +private: + uploadFinish_f mFinishFn; + std::string mBuffer; +}; + +//------------------------------------------------------------------------- class LLBufferedAssetUploadInfo : public LLResourceUploadInfo { public: diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h index 549778a841..b5841772ed 100644 --- a/indra/newview/llviewercamera.h +++ b/indra/newview/llviewercamera.h @@ -47,15 +47,14 @@ public: typedef enum { CAMERA_WORLD = 0, - CAMERA_SHADOW0, - CAMERA_SHADOW1, - CAMERA_SHADOW2, - CAMERA_SHADOW3, - CAMERA_SHADOW4, - CAMERA_SHADOW5, + CAMERA_SUN_SHADOW0, + CAMERA_SUN_SHADOW1, + CAMERA_SUN_SHADOW2, + CAMERA_SUN_SHADOW3, + CAMERA_SPOT_SHADOW0, + CAMERA_SPOT_SHADOW1, CAMERA_WATER0, CAMERA_WATER1, - CAMERA_GI_SOURCE, NUM_CAMERAS } eCameraID; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 602597a86b..9682945208 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -434,9 +434,25 @@ static bool handleRenderLocalLightsChanged(const LLSD& newvalue) return true; } +static bool handleRenderPBRChanged(const LLSD& newvalue) +{ + if (gPipeline.isInit()) + { + LLPipeline::refreshCachedSettings(); + gPipeline.updateRenderDeferred(); + gPipeline.releaseGLBuffers(); + gPipeline.createGLBuffers(); + gPipeline.resetVertexBuffers(); + LLViewerShaderMgr::instance()->setShaders(); + } + return true; +} + +#if 0 // DEPRECATED +// NOTE: may be triggered by RenderDeferred OR RenderPBR changing, don't trust "newvalue" static bool handleRenderDeferredChanged(const LLSD& newvalue) { - LLRenderTarget::sUseFBO = newvalue.asBoolean(); + LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred"); if (gPipeline.isInit()) { LLPipeline::refreshCachedSettings(); @@ -470,13 +486,7 @@ static bool handleRenderBumpChanged(const LLSD& newval) } return true; } - -static bool handleRenderDebugGLChanged(const LLSD& newvalue) -{ - gDebugGL = newvalue.asBoolean() || gDebugSession; - gGL.clearErrors(); - return true; -} +#endif static bool handleRenderDebugPipelineChanged(const LLSD& newvalue) { @@ -663,8 +673,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderGlowResolutionPow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); - gSavedSettings.getControl("RenderAvatarCloth")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); - gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + // DEPRECATED -- gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2)); gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2)); @@ -680,14 +689,14 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); - gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleRenderBumpChanged, _2)); + // DEPRECATED - gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleRenderBumpChanged, _2)); gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderVSyncEnable")->getSignal()->connect(boost::bind(&handleVSyncChanged, _2)); gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); - gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _2)); gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2)); gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _2)); - gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleRenderDeferredChanged, _2)); + // DEPRECATED - gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleRenderDeferredChanged, _2)); + gSavedSettings.getControl("RenderPBR")->getSignal()->connect(boost::bind(&handleRenderPBRChanged, _2)); gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderPerformanceTest")->getSignal()->connect(boost::bind(&handleRenderPerfTestChanged, _2)); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 4fc1bdbec3..77b84c6789 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -97,6 +97,7 @@ BOOL gResizeScreenTexture = FALSE; BOOL gResizeShadowTexture = FALSE; BOOL gWindowResized = FALSE; BOOL gSnapshot = FALSE; +BOOL gCubeSnapshot = FALSE; BOOL gShaderProfileFrame = FALSE; // This is how long the sim will try to teleport you before giving up. @@ -193,15 +194,23 @@ void display_update_camera() // Cut draw distance in half when customizing avatar, // but on the viewer only. F32 final_far = gAgentCamera.mDrawDistance; - if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) + if (gCubeSnapshot) + { + final_far = gSavedSettings.getF32("RenderReflectionProbeDrawDistance"); + } + else if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) + { final_far *= 0.5f; } LLViewerCamera::getInstance()->setFar(final_far); gViewerWindow->setup3DRender(); - // Update land visibility too - LLWorld::getInstance()->setLandFarClip(final_far); + if (!gCubeSnapshot) + { + // Update land visibility too + LLWorld::getInstance()->setLandFarClip(final_far); + } } // Write some stats to LL_INFOS() @@ -905,19 +914,19 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (LLPipeline::sRenderDeferred) { - gPipeline.mDeferredScreen.bindTarget(); + gPipeline.mRT->deferredScreen.bindTarget(); glClearColor(1, 0, 1, 1); - gPipeline.mDeferredScreen.clear(); + gPipeline.mRT->deferredScreen.clear(); } else { - gPipeline.mScreen.bindTarget(); + gPipeline.mRT->screen.bindTarget(); if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders()) { const LLColor4 &col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor(); glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); } - gPipeline.mScreen.clear(); + gPipeline.mRT->screen.clear(); } gGL.setColorMask(true, false); @@ -987,7 +996,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush"); - LLRenderTarget &rt = (gPipeline.sRenderDeferred ? gPipeline.mDeferredScreen : gPipeline.mScreen); + LLRenderTarget &rt = (gPipeline.sRenderDeferred ? gPipeline.mRT->deferredScreen : gPipeline.mRT->screen); rt.flush(); if (rt.sUseFBO) @@ -999,7 +1008,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (LLPipeline::sRenderDeferred) { - gPipeline.renderDeferredLighting(&gPipeline.mScreen); + gPipeline.renderDeferredLighting(&gPipeline.mRT->screen); } LLPipeline::sUnderWaterRender = FALSE; @@ -1046,6 +1055,113 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } } +// WIP simplified copy of display() that does minimal work +void display_cube_face() +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER); + LL_PROFILE_GPU_ZONE("display cube face"); + + llassert(!gSnapshot); + llassert(!gTeleportDisplay); + llassert(LLPipeline::sRenderDeferred); + llassert(LLStartUp::getStartupState() >= STATE_PRECACHE); + llassert(!LLAppViewer::instance()->logoutRequestSent()); + llassert(!gRestoreGL); + llassert(!gUseWireframe); + + bool rebuild = false; + + LLGLSDefault gls_default; + LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL); + + LLVertexBuffer::unbind(); + + gPipeline.disableLights(); + + gPipeline.mBackfaceCull = TRUE; + + gViewerWindow->setup3DViewport(); + + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { //don't draw hud objects in this frame + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES)) + { //don't draw hud particles in this frame + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); + } + + display_update_camera(); + + LLSpatialGroup::sNoDelete = TRUE; + + S32 occlusion = LLPipeline::sUseOcclusion; + LLPipeline::sUseOcclusion = 0; // occlusion data is from main camera point of view, don't read or write it during cube snapshots + //gDepthDirty = TRUE; //let "real" render pipe know it can't trust the depth buffer for occlusion data + + static LLCullResult result; + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater(); + gPipeline.updateCull(*LLViewerCamera::getInstance(), result); + + gGL.setColorMask(true, true); + glClearColor(0, 0, 0, 0); + gPipeline.generateSunShadow(*LLViewerCamera::getInstance()); + + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + { + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + gPipeline.stateSort(*LLViewerCamera::getInstance(), result); + + if (rebuild) + { + ////////////////////////////////////// + // + // rebuildPools + // + // + gPipeline.rebuildPools(); + stop_glerror(); + } + } + + LLPipeline::sUseOcclusion = occlusion; + + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart"); + + LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; + + gGL.setColorMask(true, true); + + gPipeline.mRT->deferredScreen.bindTarget(); + glClearColor(1, 0, 1, 1); + gPipeline.mRT->deferredScreen.clear(); + + gGL.setColorMask(true, false); + + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + + gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance()); + + gGL.setColorMask(true, true); + + gPipeline.mRT->deferredScreen.flush(); + + gPipeline.renderDeferredLighting(&gPipeline.mRT->screen); + + LLPipeline::sUnderWaterRender = FALSE; + + // Finalize scene + gPipeline.renderFinalize(); + + LLSpatialGroup::sNoDelete = FALSE; + gPipeline.clearReferences(); + + gPipeline.rebuildGroups(); +} + void render_hud_attachments() { gGL.matrixMode(LLRender::MM_PROJECTION); @@ -1240,7 +1356,7 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); - + LL_PROFILE_GPU_ZONE("ui"); LLGLState::checkStates(); glh::matrix4f saved_view = get_current_modelview(); @@ -1323,7 +1439,7 @@ static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); void swap() { LL_RECORD_BLOCK_TIME(FTM_SWAP); - + LL_PROFILE_GPU_ZONE("swap"); if (gDisplaySwapBuffers) { gViewerWindow->getWindow()->swapBuffers(); @@ -1485,7 +1601,7 @@ void render_ui_2d() LLView::sIsRectDirty = false; LLRect t_rect; - gPipeline.mUIScreen.bindTarget(); + gPipeline.mRT->uiScreen.bindTarget(); gGL.setColorMask(true, true); { static const S32 pad = 8; @@ -1517,7 +1633,7 @@ void render_ui_2d() gViewerWindow->draw(); } - gPipeline.mUIScreen.flush(); + gPipeline.mRT->uiScreen.flush(); gGL.setColorMask(true, false); LLView::sDirtyRect = t_rect; @@ -1527,7 +1643,7 @@ void render_ui_2d() LLGLDisable blend(GL_BLEND); S32 width = gViewerWindow->getWindowWidthScaled(); S32 height = gViewerWindow->getWindowHeightScaled(); - gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen); + gGL.getTexUnit(0)->bind(&gPipeline.mRT->uiScreen); gGL.begin(LLRender::TRIANGLE_STRIP); gGL.color4f(1,1,1,1); gGL.texCoord2f(0, 0); gGL.vertex2i(0, 0); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 5a3a358173..2daa919f5c 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -151,6 +151,7 @@ #include "llinspectobject.h" #include "llinspectremoteobject.h" #include "llinspecttoast.h" +#include "llmaterialeditor.h" #include "llmoveview.h" #include "llfloaterimnearbychat.h" #include "llpanelblockedlist.h" @@ -332,6 +333,8 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("save_camera_preset", "floater_save_camera_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSaveCameraPreset>); LLFloaterReg::add("script_colors", "floater_script_ed_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptEdPrefs>); + LLFloaterReg::add("material_editor", "floater_material_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLMaterialEditor>); + LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build<LLFloaterTelehub>); LLFloaterReg::add("test_inspectors", "floater_test_inspectors.xml", &LLFloaterReg::build<LLFloaterTestInspectors>); //LLFloaterReg::add("test_list_view", "floater_test_list_view.xml",&LLFloaterReg::build<LLFloaterTestListView>); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 55ac817479..2265379ce4 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -147,6 +147,7 @@ LLLocalizedInventoryItemsDictionary::LLLocalizedInventoryItemsDictionary() mInventoryItemsDict["Invalid Wearable"] = LLTrans::getString("Invalid Wearable"); mInventoryItemsDict["New Gesture"] = LLTrans::getString("New Gesture"); + mInventoryItemsDict["New Material"] = LLTrans::getString("New Material"); mInventoryItemsDict["New Script"] = LLTrans::getString("New Script"); mInventoryItemsDict["New Folder"] = LLTrans::getString("New Folder"); mInventoryItemsDict["New Note"] = LLTrans::getString("New Note"); @@ -1672,6 +1673,7 @@ void remove_folder_contents(const LLUUID& category, bool keep_outfit_links, const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not) const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not) const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) +const std::string NEW_MATERIAL_NAME = "New Material"; // *TODO:Translate? (probably not) // ! REFACTOR ! Really need to refactor this so that it's not a bunch of if-then statements... void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, const LLSD& userdata, const LLUUID& default_parent_uuid) @@ -1727,6 +1729,15 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLFolderBridge *bridge, LLInventoryType::IT_GESTURE, PERM_ALL); // overridden in create_new_item } + else if ("material" == type_name) + { + const LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL); + create_new_item(NEW_MATERIAL_NAME, + parent_id, + LLAssetType::AT_MATERIAL, + LLInventoryType::IT_MATERIAL, + PERM_ALL); // overridden in create_new_item + } else if (("sky" == type_name) || ("water" == type_name) || ("daycycle" == type_name)) { LLSettingsType::type_e stype(LLSettingsType::ST_NONE); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index d95948ac04..6d61193a56 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -267,16 +267,11 @@ void handle_reset_view(); void handle_duplicate_in_place(void*); - void handle_object_owner_self(void*); void handle_object_owner_permissive(void*); void handle_object_lock(void*); void handle_object_asset_ids(void*); void force_take_copy(void*); -#ifdef _CORY_TESTING -void force_export_copy(void*); -void force_import_geometry(void*); -#endif void handle_force_parcel_owner_to_me(void*); void handle_force_parcel_to_content(void*); @@ -398,7 +393,19 @@ void set_merchant_SLM_menu() // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(TRUE); LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); - gToolBarView->enableCommand(command->id(), true); + gToolBarView->enableCommand(command->id(), true); + + const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + if (marketplacelistings_id.isNull()) + { + U32 mkt_status = LLMarketplaceData::instance().getSLMStatus(); + bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT); + if (is_merchant) + { + gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true); + LL_WARNS("SLM") << "Creating the marketplace listings folder for a merchant" << LL_ENDL; + } + } } void check_merchant_status(bool force) @@ -1081,6 +1088,10 @@ U64 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_IMPOSTORS; } + else if ("reflection probes" == info_display) + { + return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES; + } else { LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; @@ -2336,21 +2347,6 @@ class LLAdvancedEnableRenderDeferred: public view_listener_t } }; -///////////////////////////////////// -// Enable Deferred Rendering sub-options -///////////////////////////////////// -class LLAdvancedEnableRenderDeferredOptions: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gGLManager.mHasFramebufferObject && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1 && - LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 && gSavedSettings.getBOOL("RenderDeferred"); - return new_value; - } -}; - - - ////////////////// // ADMIN STATUS // ////////////////// @@ -2705,6 +2701,32 @@ void handle_object_touch() send_ObjectDeGrab_message(object, pick); } +void handle_object_show_original() +{ + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (!object) + { + return; + } + + LLViewerObject *parent = (LLViewerObject*)object->getParent(); + while (parent) + { + if(parent->isAvatar()) + { + break; + } + object = parent; + parent = (LLViewerObject*)parent->getParent(); + } + + if (!object || object->isAvatar()) + { + return; + } + + show_item_original(object->getAttachmentItemID()); +} static void init_default_item_label(const std::string& item_name) @@ -4169,23 +4191,9 @@ bool is_object_sittable() } } - // only works on pie menu -void handle_object_sit_or_stand() +void handle_object_sit(LLViewerObject *object, const LLVector3 &offset) { - LLPickInfo pick = LLToolPie::getInstance()->getPick(); - LLViewerObject *object = pick.getObject();; - if (!object || pick.mPickType == LLPickInfo::PICK_FLORA) - { - return; - } - - if (sitting_on_selection()) - { - gAgent.standUp(); - return; - } - // get object selection offset if (object && object->getPCode() == LL_PCODE_VOLUME) @@ -4197,12 +4205,42 @@ void handle_object_sit_or_stand() gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->nextBlockFast(_PREHASH_TargetObject); gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); - gMessageSystem->addVector3Fast(_PREHASH_Offset, pick.mObjectOffset); + gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); object->getRegion()->sendReliableMessage(); } } +void handle_object_sit_or_stand() +{ + LLPickInfo pick = LLToolPie::getInstance()->getPick(); + LLViewerObject *object = pick.getObject(); + if (!object || pick.mPickType == LLPickInfo::PICK_FLORA) + { + return; + } + + if (sitting_on_selection()) + { + gAgent.standUp(); + return; + } + + handle_object_sit(object, pick.mObjectOffset); +} + +void handle_object_sit(const LLUUID& object_id) +{ + LLViewerObject* obj = gObjectList.findObject(object_id); + if (!obj) + { + return; + } + + LLVector3 offset(0, 0, 0); + handle_object_sit(obj, offset); +} + void near_sit_down_point(BOOL success, void *) { if (success) @@ -6337,6 +6375,24 @@ class LLAvatarResetSkeletonAndAnimations : public view_listener_t } }; +class LLAvatarResetSelfSkeletonAndAnimations : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + else + { + gAgentAvatarp->resetSkeleton(true); + } + return true; + } +}; + + class LLAvatarAddContact : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -7964,6 +8020,18 @@ class LLToolsSelectOnlyMovableObjects : public view_listener_t } }; +class LLToolsSelectInvisibleObjects : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + BOOL cur_val = gSavedSettings.getBOOL("SelectInvisibleObjects"); + + gSavedSettings.setBOOL("SelectInvisibleObjects", !cur_val); + + return true; + } +}; + class LLToolsSelectBySurrounding : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -8296,6 +8364,12 @@ void handle_cache_clear_immediately() LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately); } +void handle_rebuild_reflection_probes() +{ + gPipeline.mReflectionMapManager.rebuild(); +} + + void handle_web_content_test(const LLSD& param) { std::string url = param.asString(); @@ -9187,6 +9261,7 @@ void initialize_menus() view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); + view_listener_t::addMenu(new LLToolsSelectInvisibleObjects(), "Tools.SelectInvisibleObjects"); view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); @@ -9256,9 +9331,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); // Develop > Render view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion"); - view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO"); - view_listener_t::addMenu(new LLAdvancedEnableRenderDeferred(), "Advanced.EnableRenderDeferred"); - view_listener_t::addMenu(new LLAdvancedEnableRenderDeferredOptions(), "Advanced.EnableRenderDeferredOptions"); + view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); @@ -9392,6 +9465,8 @@ void initialize_menus() //Develop (clear cache immediately) commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); + //Develop (override environment map) + commit.add("Develop.RebuildReflectionProbes", boost::bind(&handle_rebuild_reflection_probes)); // Admin >Object view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); @@ -9443,6 +9518,7 @@ void initialize_menus() view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); + view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); @@ -9453,6 +9529,7 @@ void initialize_menus() // Object pie menu view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); commit.add("Object.Touch", boost::bind(&handle_object_touch)); + commit.add("Object.ShowOriginal", boost::bind(&handle_object_show_original)); commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); commit.add("Object.Delete", boost::bind(&handle_object_delete)); view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 36b6971c81..a90b32c984 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -135,6 +135,7 @@ void handle_save_snapshot(void *); void handle_toggle_flycam(); void handle_object_sit_or_stand(); +void handle_object_sit(const LLUUID& object_id); void handle_give_money_dialog(); bool enable_pay_object(); bool enable_buy_object(); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 28ff69eaf5..ffa2ce865e 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -37,6 +37,7 @@ #include "llbuycurrencyhtml.h" #include "llfloatermap.h" #include "llfloatermodelpreview.h" +#include "llmaterialeditor.h" #include "llfloatersnapshot.h" #include "llfloateroutfitsnapshot.h" #include "llimage.h" @@ -101,6 +102,20 @@ class LLFileEnableUploadModel : public view_listener_t } }; +class LLFileEnableUploadMaterial : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLMaterialEditor* me = (LLMaterialEditor*)LLFloaterReg::findInstance("material_editor"); + if (me && me->isShown()) + { + return false; + } + + return true; + } +}; + class LLMeshEnabled : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -234,6 +249,16 @@ LLFilePickerReplyThread::~LLFilePickerReplyThread() delete mFailureSignal; } +void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type & failure_cb) +{ + (new LLFilePickerReplyThread(cb, filter, get_multiple, failure_cb))->getFile(); +} + +void LLFilePickerReplyThread::startPicker(const file_picked_signal_t::slot_type & cb, LLFilePicker::ESaveFilter filter, const std::string & proposed_name, const file_picked_signal_t::slot_type & failure_cb) +{ + (new LLFilePickerReplyThread(cb, filter, proposed_name, failure_cb))->getFile(); +} + void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames) { if (filenames.empty()) @@ -255,13 +280,13 @@ void LLFilePickerReplyThread::notify(const std::vector<std::string>& filenames) LLMediaFilePicker::LLMediaFilePicker(LLPluginClassMedia* plugin, LLFilePicker::ELoadFilter filter, bool get_multiple) : LLFilePickerThread(filter, get_multiple), - mPlugin(plugin->getSharedPrt()) + mPlugin(plugin->getSharedPtr()) { } LLMediaFilePicker::LLMediaFilePicker(LLPluginClassMedia* plugin, LLFilePicker::ESaveFilter filter, const std::string &proposed_name) : LLFilePickerThread(filter, proposed_name), - mPlugin(plugin->getSharedPrt()) + mPlugin(plugin->getSharedPtr()) { } @@ -277,14 +302,12 @@ void LLMediaFilePicker::notify(const std::vector<std::string>& filenames) static std::string SOUND_EXTENSIONS = "wav"; static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png"; static std::string ANIM_EXTENSIONS = "bvh anim"; -#ifdef _CORY_TESTING -static std::string GEOMETRY_EXTENSIONS = "slg"; -#endif static std::string XML_EXTENSIONS = "xml"; static std::string SLOBJECT_EXTENSIONS = "slobject"; #endif static std::string ALL_FILE_EXTENSIONS = "*.*"; static std::string MODEL_EXTENSIONS = "dae"; +static std::string MATERIAL_EXTENSIONS = "gltf glb"; std::string build_extensions_string(LLFilePicker::ELoadFilter filter) { @@ -301,10 +324,8 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter) return SLOBJECT_EXTENSIONS; case LLFilePicker::FFLOAD_MODEL: return MODEL_EXTENSIONS; -#ifdef _CORY_TESTING - case LLFilePicker::FFLOAD_GEOMETRY: - return GEOMETRY_EXTENSIONS; -#endif + case LLFilePicker::FFLOAD_MATERIAL: + return MATERIAL_EXTENSIONS; case LLFilePicker::FFLOAD_XML: return XML_EXTENSIONS; case LLFilePicker::FFLOAD_ALL: @@ -560,7 +581,7 @@ class LLFileUploadImage : public view_listener_t { gAgentCamera.changeCameraToDefault(); } - (new LLFilePickerReplyThread(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_IMAGE, false); return true; } }; @@ -573,7 +594,16 @@ class LLFileUploadModel : public view_listener_t return TRUE; } }; - + +class LLFileUploadMaterial : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLMaterialEditor::importMaterial(); + return TRUE; + } +}; + class LLFileUploadSound : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -582,7 +612,7 @@ class LLFileUploadSound : public view_listener_t { gAgentCamera.changeCameraToDefault(); } - (new LLFilePickerReplyThread(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_WAV, false); return true; } }; @@ -595,7 +625,7 @@ class LLFileUploadAnim : public view_listener_t { gAgentCamera.changeCameraToDefault(); } - (new LLFilePickerReplyThread(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&upload_single_file, _1, _2), LLFilePicker::FFLOAD_ANIM, false); return true; } }; @@ -608,7 +638,7 @@ class LLFileUploadBulk : public view_listener_t { gAgentCamera.changeCameraToDefault(); } - (new LLFilePickerReplyThread(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&upload_bulk, _1, _2), LLFilePicker::FFLOAD_ALL, true); return true; } }; @@ -1104,6 +1134,7 @@ void init_menu_file() view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); + view_listener_t::addCommit(new LLFileUploadMaterial(), "File.UploadMaterial"); view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index beeac418d9..5c2caf9c51 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -115,14 +115,18 @@ class LLFilePickerReplyThread : public LLFilePickerThread public: typedef boost::signals2::signal<void(const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)> file_picked_signal_t; - - LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); - LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); - ~LLFilePickerReplyThread(); + + static void startPicker(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); + static void startPicker(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); virtual void notify(const std::vector<std::string>& filenames); private: + LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ELoadFilter filter, bool get_multiple, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); + LLFilePickerReplyThread(const file_picked_signal_t::slot_type& cb, LLFilePicker::ESaveFilter filter, const std::string &proposed_name, const file_picked_signal_t::slot_type& failure_cb = file_picked_signal_t()); + ~LLFilePickerReplyThread(); + +private: LLFilePicker::ELoadFilter mLoadFilter; LLFilePicker::ESaveFilter mSaveFilter; file_picked_signal_t* mFilePickedSignal; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index a886303563..e959f24f1f 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1414,7 +1414,8 @@ bool check_asset_previewable(const LLAssetType::EType asset_type) (asset_type == LLAssetType::AT_TEXTURE) || (asset_type == LLAssetType::AT_ANIMATION) || (asset_type == LLAssetType::AT_SCRIPT) || - (asset_type == LLAssetType::AT_SOUND); + (asset_type == LLAssetType::AT_SOUND) || + (asset_type == LLAssetType::AT_MATERIAL); } void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name) @@ -1519,6 +1520,9 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam case LLAssetType::AT_SOUND: LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus); break; + case LLAssetType::AT_MATERIAL: + LLFloaterReg::showInstance("material editor", LLSD(obj_id), take_focus); + break; default: LL_DEBUGS("Messaging") << "No preview method for previewable asset type : " << LLAssetType::lookupHumanReadable(asset_type) << LL_ENDL; break; @@ -3334,6 +3338,13 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // trigger a control event. U32 control_flags = gAgent.getControlFlags(); + // Rotation into both directions should cancel out + U32 mask = AGENT_CONTROL_YAW_POS | AGENT_CONTROL_YAW_NEG; + if ((control_flags & mask) == mask) + { + control_flags &= ~mask; + } + MASK key_mask = gKeyboard->currentMask(TRUE); if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) @@ -5805,15 +5816,15 @@ void process_script_question(LLMessageSystem *msg, void **user_data) if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit) continue; - if (script_perm.question == "JoinAnExperience") - { // Some experience only permissions do not have an explicit permission bit. Add them here. - script_question += " " + LLTrans::getString("ForceSitAvatar") + "\n"; + if (LLTrans::getString(script_perm.question).empty()) + { + continue; } script_question += " " + LLTrans::getString(script_perm.question) + "\n"; } } - + args["QUESTIONS"] = script_question; if (known_questions != questions) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index a95636ff23..bdc47e0c50 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -107,6 +107,7 @@ #include "llcleanup.h" #include "llcallstack.h" #include "llmeshrepository.h" +#include "llgltfmateriallist.h" #include "llgl.h" //#define DEBUG_UPDATE_TYPE @@ -259,7 +260,6 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mTEImages(NULL), mTENormalMaps(NULL), mTESpecularMaps(NULL), - mGLName(0), mbCanSelect(TRUE), mFlags(0), mPhysicsShapeType(0), @@ -343,6 +343,13 @@ LLViewerObject::~LLViewerObject() { deleteTEImages(); + // unhook from reflection probe manager + if (mReflectionProbe.notNull()) + { + mReflectionProbe->mViewerObject = nullptr; + mReflectionProbe = nullptr; + } + if(mInventory) { mInventory->clear(); // will deref and delete entries @@ -400,6 +407,11 @@ void LLViewerObject::deleteTEImages() delete[] mTESpecularMaps; mTESpecularMaps = NULL; } + + mGLTFAlbedoMaps.clear(); + mGLTFNormalMaps.clear(); + mGLTFMetallicRoughnessMaps.clear(); + mGLTFEmissiveMaps.clear(); } void LLViewerObject::markDead() @@ -4566,6 +4578,7 @@ BOOL LLViewerObject::lineSegmentIntersect(const LLVector4a& start, const LLVecto S32 face, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, @@ -4724,6 +4737,11 @@ void LLViewerObject::setNumTEs(const U8 num_tes) mTEImages = new_images; mTENormalMaps = new_normmaps; mTESpecularMaps = new_specmaps; + + mGLTFAlbedoMaps.resize(num_tes); + mGLTFNormalMaps.resize(num_tes); + mGLTFMetallicRoughnessMaps.resize(num_tes); + mGLTFEmissiveMaps.resize(num_tes); } else { @@ -4852,23 +4870,28 @@ void LLViewerObject::updateAvatarMeshVisibility(const LLUUID& id, const LLUUID& } } -void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry) + +void LLViewerObject::setTE(const U8 te, const LLTextureEntry& texture_entry) { - LLUUID old_image_id; - if (getTE(te)) - { - old_image_id = getTE(te)->getID(); - } - - LLPrimitive::setTE(te, texture_entry); + LLUUID old_image_id; + if (getTE(te)) + { + old_image_id = getTE(te)->getID(); + } - const LLUUID& image_id = getTE(te)->getID(); - LLViewerTexture* bakedTexture = getBakedTextureForMagicId(image_id); - mTEImages[te] = bakedTexture ? bakedTexture : LLViewerTextureManager::getFetchedTexture(image_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + LLPrimitive::setTE(te, texture_entry); - - updateAvatarMeshVisibility(image_id,old_image_id); + const LLUUID& image_id = getTE(te)->getID(); + LLViewerTexture* bakedTexture = getBakedTextureForMagicId(image_id); + mTEImages[te] = bakedTexture ? bakedTexture : LLViewerTextureManager::getFetchedTexture(image_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + + updateAvatarMeshVisibility(image_id, old_image_id); + updateTEMaterialTextures(te); +} + +void LLViewerObject::updateTEMaterialTextures(U8 te) +{ if (getTE(te)->getMaterialParams().notNull()) { const LLUUID& norm_id = getTE(te)->getMaterialParams()->getNormalID(); @@ -4877,6 +4900,47 @@ void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry) const LLUUID& spec_id = getTE(te)->getMaterialParams()->getSpecularID(); mTESpecularMaps[te] = LLViewerTextureManager::getFetchedTexture(spec_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE); } + + auto fetch_texture = [](const LLUUID& id) + { + LLViewerFetchedTexture* img = nullptr; + if (id.notNull()) + { + img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE); + img->addTextureStats(64.f * 64.f, TRUE); + } + + return img; + }; + + LLGLTFMaterial* mat = getTE(te)->getGLTFMaterial(); + LLUUID mat_id = getRenderMaterialID(te); + if (mat == nullptr && mat_id.notNull()) + { + mat = gGLTFMaterialList.getMaterial(mat_id); + getTE(te)->setGLTFMaterial(mat); + } + else if (mat_id.isNull() && mat != nullptr) + { + mat = nullptr; + getTE(te)->setGLTFMaterial(nullptr); + } + + if (mat != nullptr) + { + mGLTFAlbedoMaps[te] = fetch_texture(mat->mAlbedoId); + mGLTFNormalMaps[te] = fetch_texture(mat->mNormalId); + mGLTFMetallicRoughnessMaps[te] = fetch_texture(mat->mMetallicRoughnessId); + mGLTFEmissiveMaps[te] = fetch_texture(mat->mEmissiveId); + } + else + { + mGLTFAlbedoMaps[te] = nullptr; + mGLTFNormalMaps[te] = nullptr; + mGLTFMetallicRoughnessMaps[te] = nullptr; + mGLTFEmissiveMaps[te] = nullptr; + } + } void LLViewerObject::refreshBakeTexture() @@ -5417,7 +5481,6 @@ void LLViewerObject::fitFaceTexture(const U8 face) LL_INFOS() << "fitFaceTexture not implemented" << LL_ENDL; } - LLBBox LLViewerObject::getBoundingBoxAgent() const { LLVector3 position_agent; @@ -5502,18 +5565,6 @@ S32 LLViewerObject::countInventoryContents(LLAssetType::EType type) return count; } - -void LLViewerObject::setCanSelect(BOOL canSelect) -{ - mbCanSelect = canSelect; - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) - { - LLViewerObject* child = *iter; - child->mbCanSelect = canSelect; - } -} - void LLViewerObject::setDebugText(const std::string &utf8text) { if (utf8text.empty() && !mText) @@ -6017,6 +6068,16 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para new_block = new LLExtendedMeshParams(); break; } + case LLNetworkData::PARAMS_RENDER_MATERIAL: + { + new_block = new LLRenderMaterialParams(); + break; + } + case LLNetworkData::PARAMS_REFLECTION_PROBE: + { + new_block = new LLReflectionProbeParams(); + break; + } default: { LL_INFOS() << "Unknown param type." << LL_ENDL; @@ -6958,6 +7019,69 @@ LLVOAvatar* LLViewerObject::getAvatar() const return NULL; } +bool LLViewerObject::hasRenderMaterialParams() const +{ + return getParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL); +} + +void LLViewerObject::setHasRenderMaterialParams(bool has_materials) +{ + bool had_materials = hasRenderMaterialParams(); + + if (had_materials != has_materials) + { + if (has_materials) + { + setParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL, TRUE, true); + } + else + { + setParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL, FALSE, true); + } + } +} + +const LLUUID& LLViewerObject::getRenderMaterialID(U8 te) const +{ + LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL); + if (param_block) + { + return param_block->getMaterial(te); + } + + return LLUUID::null; +} + +void LLViewerObject::setRenderMaterialID(U8 te, const LLUUID& id) +{ + if (id.notNull()) + { + getTE(te)->setGLTFMaterial(gGLTFMaterialList.getMaterial(id)); + setHasRenderMaterialParams(true); + } + else + { + getTE(te)->setGLTFMaterial(nullptr); + } + + faceMappingChanged(); + gPipeline.markTextured(mDrawable); + + LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL); + if (param_block) + { + param_block->setMaterial(te, id); + + if (param_block->isEmpty()) + { // might be empty if id is null + setHasRenderMaterialParams(false); + } + else + { + parameterChanged(LLNetworkData::PARAMS_RENDER_MATERIAL, true); + } + } +} class ObjectPhysicsProperties : public LLHTTPNode { diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index bef8e3e7e3..109c96dc9c 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -43,6 +43,7 @@ #include "llvertexbuffer.h" #include "llbbox.h" #include "llrigginginfo.h" +#include "llreflectionmap.h" class LLAgent; // TODO: Get rid of this. class LLAudioSource; @@ -178,6 +179,13 @@ public: const std::string& getAttachmentItemName() const; virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment + + bool hasRenderMaterialParams() const; + void setHasRenderMaterialParams(bool has_params); + + const LLUUID& getRenderMaterialID(U8 te) const; + void setRenderMaterialID(U8 te, const LLUUID& id); + virtual BOOL isHUDAttachment() const { return FALSE; } virtual BOOL isTempAttachment() const; @@ -199,6 +207,7 @@ public: // Graphical stuff for objects - maybe broken out into render class later? virtual void updateTextures(); + virtual void faceMappingChanged() {} virtual void boostTexturePriority(BOOL boost_children = TRUE); // When you just want to boost priority of this object virtual LLDrawable* createDrawable(LLPipeline *pipeline); @@ -238,6 +247,7 @@ public: virtual BOOL isMesh() const { return FALSE; } virtual BOOL isRiggedMesh() const { return FALSE; } virtual BOOL hasLightTexture() const { return FALSE; } + virtual BOOL isReflectionProbe() const { return FALSE; } // This method returns true if the object is over land owned by // the agent, one of its groups, or it encroaches and @@ -279,6 +289,7 @@ public: S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, // which face was hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point @@ -318,6 +329,7 @@ public: /*virtual*/ void setNumTEs(const U8 num_tes); /*virtual*/ void setTE(const U8 te, const LLTextureEntry &texture_entry); + void updateTEMaterialTextures(U8 te); /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); /*virtual*/ S32 setTENormalMap(const U8 te, const LLUUID &uuid); /*virtual*/ S32 setTESpecularMap(const U8 te, const LLUUID &uuid); @@ -356,6 +368,12 @@ public: LLViewerTexture *getTEImage(const U8 te) const; LLViewerTexture *getTENormalMap(const U8 te) const; LLViewerTexture *getTESpecularMap(const U8 te) const; + + LLViewerTexture* getGLTFAlbedoMap(U8 te) const { return mGLTFAlbedoMaps[te]; } + LLViewerTexture* getGLTFNormalMap(U8 te) const { return mGLTFNormalMaps[te]; } + LLViewerTexture* getGLTFEmissiveMap(U8 te) const { return mGLTFEmissiveMaps[te]; } + LLViewerTexture* getGLTFMetallicRoughnessMap(U8 te) const { return mGLTFMetallicRoughnessMaps[te]; } + bool isImageAlphaBlended(const U8 te) const; @@ -420,8 +438,6 @@ public: void sendMaterialUpdate() const; - void setCanSelect(BOOL canSelect); - void setDebugText(const std::string &utf8text); void initHudText(); void restoreHudText(); @@ -674,10 +690,17 @@ public: LLPointer<LLViewerTexture> *mTEImages; LLPointer<LLViewerTexture> *mTENormalMaps; LLPointer<LLViewerTexture> *mTESpecularMaps; + + std::vector<LLPointer<LLViewerTexture> > mGLTFAlbedoMaps; + std::vector<LLPointer<LLViewerTexture> > mGLTFNormalMaps; + std::vector<LLPointer<LLViewerTexture> > mGLTFMetallicRoughnessMaps; + std::vector<LLPointer<LLViewerTexture> > mGLTFEmissiveMaps; - // Selection, picking and rendering variables - U32 mGLName; // GL "name" used by selection code - BOOL mbCanSelect; // true if user can select this object by clicking + + + // true if user can select this object by clicking under any circumstances (even if pick_unselectable is true) + // can likely be factored out + BOOL mbCanSelect; private: // Grabbed from UPDATE_FLAGS @@ -845,7 +868,7 @@ protected: F32 mLinksetCost; F32 mPhysicsCost; F32 mLinksetPhysicsCost; - + bool mCostStale; mutable bool mPhysicsShapeUnknown; @@ -904,6 +927,11 @@ private: LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory. EObjectUpdateType mLastUpdateType; BOOL mLastUpdateCached; + +public: + // reflection probe state + bool mIsReflectionProbe = false; // if true, this object should register itself with LLReflectionProbeManager + LLPointer<LLReflectionMap> mReflectionProbe = nullptr; // reflection probe coupled to this viewer object. If not null, should be deregistered when this object is destroyed }; /////////////////// diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 0e585f13fc..389f5087e2 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -72,7 +72,7 @@ #ifdef LL_USESYSTEMLIBS #include <zlib.h> #else -#include "zlib/zlib.h" +#include "zlib-ng/zlib.h" #endif #include "object_flags.h" @@ -1339,38 +1339,13 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) } // Don't clean up mObject references, these will be cleaned up more efficiently later! - // Also, not cleaned up - removeDrawable(objectp->mDrawable); - + if(new_dead_object) { mNumDeadObjects++; } } -void LLViewerObjectList::removeDrawable(LLDrawable* drawablep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; - - if (!drawablep) - { - return; - } - - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - LLFace* facep = drawablep->getFace(i) ; - if(facep) - { - LLViewerObject* objectp = facep->getViewerObject(); - if(objectp) - { - mSelectPickList.erase(objectp); - } - } - } -} - BOOL LLViewerObjectList::killObject(LLViewerObject *objectp) { // Don't ever kill gAgentAvatarp, just force it to the agent's region @@ -1836,146 +1811,6 @@ void LLViewerObjectList::renderObjectBounds(const LLVector3 ¢er) { } -void LLViewerObjectList::generatePickList(LLCamera &camera) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - - LLViewerObject *objectp; - S32 i; - // Reset all of the GL names to zero. - for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) - { - (*iter)->mGLName = 0; - } - - mSelectPickList.clear(); - - std::vector<LLDrawable*> pick_drawables; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) - { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) - { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->cull(camera, &pick_drawables, TRUE); - } - } - } - - for (std::vector<LLDrawable*>::iterator iter = pick_drawables.begin(); - iter != pick_drawables.end(); iter++) - { - LLDrawable* drawablep = *iter; - if( !drawablep ) - continue; - - LLViewerObject* last_objectp = NULL; - for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++) - { - LLFace * facep = drawablep->getFace(face_num); - if (!facep) continue; - - LLViewerObject* objectp = facep->getViewerObject(); - - if (objectp && objectp != last_objectp) - { - mSelectPickList.insert(objectp); - last_objectp = objectp; - } - } - } - - LLHUDNameTag::addPickable(mSelectPickList); - - for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - objectp = (LLVOAvatar*) *iter; - if (!objectp->isDead()) - { - if (objectp->mDrawable.notNull() && objectp->mDrawable->isVisible()) - { - mSelectPickList.insert(objectp); - } - } - } - - // add all hud objects to pick list - if (isAgentAvatarValid()) - { - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getIsHUDAttachment()) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - if (LLViewerObject* attached_object = attachment_iter->get()) - { - mSelectPickList.insert(attached_object); - LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* childp = *iter; - if (childp) - { - mSelectPickList.insert(childp); - } - } - } - } - } - } - } - - S32 num_pickables = (S32)mSelectPickList.size() + LLHUDIcon::getNumInstances(); - - if (num_pickables != 0) - { - S32 step = (0x000fffff - GL_NAME_INDEX_OFFSET) / num_pickables; - - std::set<LLViewerObject*>::iterator pick_it; - i = 0; - for (pick_it = mSelectPickList.begin(); pick_it != mSelectPickList.end();) - { - LLViewerObject* objp = (*pick_it); - if (!objp || objp->isDead() || !objp->mbCanSelect) - { - mSelectPickList.erase(pick_it++); - continue; - } - - objp->mGLName = (i * step) + GL_NAME_INDEX_OFFSET; - i++; - ++pick_it; - } - - LLHUDIcon::generatePickIDs(i * step, step); - } -} - -LLViewerObject *LLViewerObjectList::getSelectedObject(const U32 object_id) -{ - std::set<LLViewerObject*>::iterator pick_it; - for (pick_it = mSelectPickList.begin(); pick_it != mSelectPickList.end(); ++pick_it) - { - if ((*pick_it)->mGLName == object_id) - { - return (*pick_it); - } - } - return NULL; -} - void LLViewerObjectList::addDebugBeacon(const LLVector3 &pos_agent, const std::string &string, const LLColor4 &color, diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 72b2b99004..f2cba8c259 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -77,7 +77,6 @@ public: BOOL killObject(LLViewerObject *objectp); void killObjects(LLViewerRegion *regionp); // Kill all objects owned by a particular region. void killAllObjects(); - void removeDrawable(LLDrawable* drawablep); void cleanDeadObjects(const BOOL use_timer = TRUE); // Clean up the dead object list. @@ -129,11 +128,6 @@ public: void updateAvatarVisibility(); - // Selection related stuff - void generatePickList(LLCamera &camera); - - LLViewerObject *getSelectedObject(const U32 object_id); - inline S32 getNumObjects() { return (S32) mObjects.size(); } inline S32 getNumActiveObjects() { return (S32) mActiveObjects.size(); } @@ -226,8 +220,6 @@ protected: static std::map<U64, LLUUID> sIndexAndLocalIDToUUID; - std::set<LLViewerObject *> mSelectPickList; - friend class LLViewerObject; private: diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 12624ec3a2..36b2bd4c32 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -948,6 +948,7 @@ void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_M break; case STATE_MODE_DIFF: + if (mOctreeNode) { LLSpatialSetOcclusionStateDiff setter(state); setter.traverse(mOctreeNode); @@ -955,6 +956,7 @@ void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_M break; case STATE_MODE_BRANCH: + if (mOctreeNode) { LLSpatialSetOcclusionState setter(state); setter.traverse(mOctreeNode); @@ -1024,6 +1026,7 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE break; case STATE_MODE_DIFF: + if (mOctreeNode) { LLSpatialClearOcclusionStateDiff clearer(state); clearer.traverse(mOctreeNode); @@ -1031,6 +1034,7 @@ void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE break; case STATE_MODE_BRANCH: + if (mOctreeNode) { LLSpatialClearOcclusionState clearer(state); clearer.traverse(mOctreeNode); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 67ad72e997..9b7f4ff30d 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -3060,6 +3060,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("ObjectAnimation"); capabilityNames.append("ObjectMedia"); capabilityNames.append("ObjectMediaNavigate"); + capabilityNames.append("ObjectNavMeshProperties"); capabilityNames.append("ParcelPropertiesUpdate"); capabilityNames.append("ParcelVoiceInfoRequest"); capabilityNames.append("ProductInfoRequest"); @@ -3095,6 +3096,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("UpdateScriptTask"); capabilityNames.append("UpdateSettingsAgentInventory"); capabilityNames.append("UpdateSettingsTaskInventory"); + capabilityNames.append("UpdateMaterialAgentInventory"); + capabilityNames.append("UpdateMaterialTaskInventory"); capabilityNames.append("UploadBakedTexture"); capabilityNames.append("UserInfo"); capabilityNames.append("ViewerAsset"); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 086b433c72..0d9670d9ca 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -49,6 +49,8 @@ #include "lljoint.h" #include "llskinningutil.h" +//#pragma optimize("", off) + static LLStaticHashedString sTexture0("texture0"); static LLStaticHashedString sTexture1("texture1"); static LLStaticHashedString sTex0("tex0"); @@ -82,6 +84,9 @@ LLGLSLShader gOcclusionCubeProgram; LLGLSLShader gCustomAlphaProgram; LLGLSLShader gGlowCombineProgram; LLGLSLShader gSplatTextureRectProgram; +LLGLSLShader gReflectionMipProgram; +LLGLSLShader gRadianceGenProgram; +LLGLSLShader gIrradianceGenProgram; LLGLSLShader gGlowCombineFXAAProgram; LLGLSLShader gTwoTextureAddProgram; LLGLSLShader gTwoTextureCompareProgram; @@ -258,6 +263,8 @@ LLGLSLShader gNormalMapGenProgram; // Deferred materials shaders LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; LLGLSLShader gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2]; +LLGLSLShader gDeferredPBROpaqueProgram; +LLGLSLShader gDeferredSkinnedPBROpaqueProgram; //helper for making a rigged variant of a given shader bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader) @@ -486,11 +493,12 @@ void LLViewerShaderMgr::setShaders() llassert((gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10)); - bool canRenderDeferred = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); - bool hasWindLightShaders = LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"); + //bool canRenderDeferred = true; // DEPRECATED -- LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); + //bool hasWindLightShaders = true; // DEPRECATED -- LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"); S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); - bool doingWindLight = hasWindLightShaders && gSavedSettings.getBOOL("WindLightUseAtmosShaders"); - bool useRenderDeferred = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred"); + bool pbr = gSavedSettings.getBOOL("RenderPBR"); + bool doingWindLight = true; //DEPRECATED -- hasWindLightShaders&& gSavedSettings.getBOOL("WindLightUseAtmosShaders"); + bool useRenderDeferred = true; //DEPRECATED -- doingWindLight&& canRenderDeferred&& gSavedSettings.getBOOL("RenderDeferred"); S32 light_class = 3; S32 interface_class = 2; @@ -528,6 +536,11 @@ void LLViewerShaderMgr::setShaders() } } + if (deferred_class > 0 && pbr) + { + deferred_class = 3; + } + if (doingWindLight) { // user has disabled WindLight in their settings, downgrade @@ -556,15 +569,14 @@ void LLViewerShaderMgr::setShaders() mShaderLevel[SHADER_DEFERRED] = deferred_class; mShaderLevel[SHADER_TRANSFORM] = transform_class; - BOOL loaded = loadBasicShaders(); - if (loaded) + std::string shader_name = loadBasicShaders(); + if (shader_name.empty()) { LL_INFOS() << "Loaded basic shaders." << LL_ENDL; } else { - LL_ERRS() << "Unable to load basic shaders, verify graphics driver installed and current." << LL_ENDL; - llassert(loaded); + LL_ERRS() << "Unable to load basic shader " << shader_name << ", verify graphics driver installed and current." << LL_ENDL; reentrance = false; // For hygiene only, re-try probably helps nothing return; } @@ -572,7 +584,7 @@ void LLViewerShaderMgr::setShaders() gPipeline.mShadersLoaded = true; // Load all shaders to set max levels - loaded = loadShadersEnvironment(); + BOOL loaded = loadShadersEnvironment(); if (loaded) { @@ -641,7 +653,6 @@ void LLViewerShaderMgr::setShaders() } if (loaded) - { loaded = loadTransformShaders(); if (loaded) @@ -660,70 +671,27 @@ void LLViewerShaderMgr::setShaders() // Load max avatar shaders to set the max level mShaderLevel[SHADER_AVATAR] = 3; mMaxAvatarShaderLevel = 3; - - if (loadShadersObject()) - { //hardware skinning is enabled and rigged attachment shaders loaded correctly - BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); + if (loadShadersObject()) + { //hardware skinning is enabled and rigged attachment shaders loaded correctly // cloth is a class3 shader - S32 avatar_class = avatar_cloth ? 3 : 1; + S32 avatar_class = 1; // Set the actual level mShaderLevel[SHADER_AVATAR] = avatar_class; loaded = loadShadersAvatar(); llassert(loaded); - - if (mShaderLevel[SHADER_AVATAR] != avatar_class) - { - if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3) - { - avatar_cloth = true; - } - else - { - avatar_cloth = false; - } - gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); - } } else { //hardware skinning not possible, neither is deferred rendering - mShaderLevel[SHADER_AVATAR] = 0; - mShaderLevel[SHADER_DEFERRED] = 0; - - gSavedSettings.setBOOL("RenderDeferred", FALSE); - gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); - - loadShadersAvatar(); // unloads - - loaded = loadShadersObject(); - llassert(loaded); + llassert(false); // SHOULD NOT BE POSSIBLE } } - if (!loaded) - { //some shader absolutely could not load, try to fall back to a simpler setting - if (gSavedSettings.getBOOL("WindLightUseAtmosShaders")) - { //disable windlight and try again - gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE); - LL_WARNS() << "Falling back to no windlight shaders." << LL_ENDL; - reentrance = false; - setShaders(); - return; - } - } - llassert(loaded); - - if (loaded && !loadShadersDeferred()) - { //everything else succeeded but deferred failed, disable deferred and try again - gSavedSettings.setBOOL("RenderDeferred", FALSE); - LL_WARNS() << "Falling back to no deferred shaders." << LL_ENDL; - reentrance = false; - setShaders(); - return; - } + loaded = loaded && loadShadersDeferred(); + llassert(loaded); if (gViewerWindow) { @@ -752,6 +720,9 @@ void LLViewerShaderMgr::unloadShaders() gCustomAlphaProgram.unload(); gGlowCombineProgram.unload(); gSplatTextureRectProgram.unload(); + gReflectionMipProgram.unload(); + gRadianceGenProgram.unload(); + gIrradianceGenProgram.unload(); gGlowCombineFXAAProgram.unload(); gTwoTextureAddProgram.unload(); gTwoTextureCompareProgram.unload(); @@ -859,7 +830,7 @@ void LLViewerShaderMgr::unloadShaders() gPipeline.mShadersLoaded = false; } -BOOL LLViewerShaderMgr::loadBasicShaders() +std::string LLViewerShaderMgr::loadBasicShaders() { // Load basic dependency shaders first // All of these have to load for any shaders to function @@ -945,8 +916,8 @@ BOOL LLViewerShaderMgr::loadBasicShaders() // Note usage of GL_VERTEX_SHADER_ARB if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB, &attribs) == 0) { - LL_SHADER_LOADING_WARNS() << "Failed to load vertex shader " << shaders[i].first << LL_ENDL; - return FALSE; + LL_WARNS("Shader") << "Failed to load vertex shader " << shaders[i].first << LL_ENDL; + return shaders[i].first; } } @@ -975,6 +946,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders() index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/deferredUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/reflectionProbeF.glsl", llmax(mShaderLevel[SHADER_DEFERRED], 1)) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); @@ -1005,12 +977,12 @@ BOOL LLViewerShaderMgr::loadBasicShaders() // Note usage of GL_FRAGMENT_SHADER_ARB if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, &attribs, index_channels[i]) == 0) { - LL_SHADER_LOADING_WARNS() << "Failed to load fragment shader " << shaders[i].first << LL_ENDL; - return FALSE; + LL_WARNS("Shader") << "Failed to load fragment shader " << shaders[i].first << LL_ENDL; + return shaders[i].first; } } - return TRUE; + return std::string(); } BOOL LLViewerShaderMgr::loadShadersEnvironment() @@ -1218,7 +1190,8 @@ BOOL LLViewerShaderMgr::loadShadersEffects() BOOL LLViewerShaderMgr::loadShadersDeferred() { - bool use_sun_shadow = mShaderLevel[SHADER_DEFERRED] > 1; + bool use_sun_shadow = mShaderLevel[SHADER_DEFERRED] > 1 && + gSavedSettings.getS32("RenderShadowDetail") > 0; BOOL ambient_kill = gSavedSettings.getBOOL("AmbientDisable"); BOOL sunlight_kill = gSavedSettings.getBOOL("SunlightDisable"); @@ -1307,6 +1280,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialProgram[i].unload(); gDeferredMaterialWaterProgram[i].unload(); } + + gDeferredPBROpaqueProgram.unload(); + gDeferredSkinnedPBROpaqueProgram.unload(); + return TRUE; } @@ -1498,6 +1475,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialProgram[i].mFeatures.hasGamma = true; gDeferredMaterialProgram[i].mFeatures.hasShadows = use_sun_shadow; + if (mShaderLevel[SHADER_DEFERRED] > 2) + { + gDeferredMaterialProgram[i].mFeatures.hasReflectionProbes = true; + gDeferredMaterialProgram[i].addPermutation("HAS_REFLECTION_PROBES", "1"); + } + if (has_skin) { gDeferredMaterialProgram[i].addPermutation("HAS_SKIN", "1"); @@ -1611,6 +1594,28 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + if (success) + { + gDeferredPBROpaqueProgram.mName = "Deferred PBR Opaque Shader"; + gDeferredPBROpaqueProgram.mFeatures.encodesNormal = true; + gDeferredPBROpaqueProgram.mFeatures.hasSrgb = true; + + gDeferredPBROpaqueProgram.mShaderFiles.clear(); + gDeferredPBROpaqueProgram.mShaderFiles.push_back(make_pair("deferred/pbropaqueV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredPBROpaqueProgram.mShaderFiles.push_back(make_pair("deferred/pbropaqueF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredPBROpaqueProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredPBROpaqueProgram.addPermutation("HAS_NORMAL_MAP", "1"); + gDeferredPBROpaqueProgram.addPermutation("HAS_SPECULAR_MAP", "1"); + gDeferredPBROpaqueProgram.addPermutation("HAS_EMISSIVE_MAP", "1"); + gDeferredPBROpaqueProgram.addPermutation("DIFFUSE_ALPHA_MODE", "0"); + + success = make_rigged_variant(gDeferredPBROpaqueProgram, gDeferredSkinnedPBROpaqueProgram); + if (success) + { + success = gDeferredPBROpaqueProgram.createShader(NULL, NULL); + } + llassert(success); + } if (success) { @@ -2181,6 +2186,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + if (gDeferredFullbrightShinyProgram.mShaderLevel > 2) + { + gDeferredFullbrightShinyProgram.addPermutation("HAS_REFLECTION_PROBES", "1"); + gDeferredFullbrightShinyProgram.mFeatures.hasReflectionProbes = true; + } success = make_rigged_variant(gDeferredFullbrightShinyProgram, gDeferredSkinnedFullbrightShinyProgram); success = success && gDeferredFullbrightShinyProgram.createShader(NULL, NULL); llassert(success); @@ -2253,6 +2263,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenProgram.mFeatures.hasGamma = true; gDeferredSoftenProgram.mFeatures.isDeferred = true; gDeferredSoftenProgram.mFeatures.hasShadows = use_sun_shadow; + gDeferredSoftenProgram.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED] > 2; gDeferredSoftenProgram.clearPermutations(); gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB)); @@ -2260,6 +2271,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + if (use_sun_shadow) + { + gDeferredSoftenProgram.addPermutation("HAS_SUN_SHADOW", "1"); + } + if (ambient_kill) { gDeferredSoftenProgram.addPermutation("AMBIENT_KILL", "1"); @@ -2278,6 +2294,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (gSavedSettings.getBOOL("RenderDeferredSSAO")) { //if using SSAO, take screen space light map into account as if shadows are enabled gDeferredSoftenProgram.mShaderLevel = llmax(gDeferredSoftenProgram.mShaderLevel, 2); + gDeferredSoftenProgram.addPermutation("HAS_SSAO", "1"); } success = gDeferredSoftenProgram.createShader(NULL, NULL); @@ -2303,6 +2320,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenWaterProgram.mFeatures.hasGamma = true; gDeferredSoftenWaterProgram.mFeatures.isDeferred = true; gDeferredSoftenWaterProgram.mFeatures.hasShadows = use_sun_shadow; + gDeferredSoftenWaterProgram.mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED] > 2; + + if (use_sun_shadow) + { + gDeferredSoftenWaterProgram.addPermutation("HAS_SUN_SHADOW", "1"); + } if (ambient_kill) { @@ -2317,6 +2340,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (local_light_kill) { gDeferredSoftenWaterProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); + gDeferredSoftenWaterProgram.addPermutation("HAS_SSAO", "1"); } if (gSavedSettings.getBOOL("RenderDeferredSSAO")) @@ -3574,7 +3598,6 @@ BOOL LLViewerShaderMgr::loadShadersInterface() } } - if (success) { gTwoTextureAddProgram.mName = "Two Texture Add Shader"; @@ -3750,6 +3773,42 @@ BOOL LLViewerShaderMgr::loadShadersInterface() success = gAlphaMaskProgram.createShader(NULL, NULL); } + if (success) + { + gReflectionMipProgram.mName = "Reflection Mip Shader"; + gReflectionMipProgram.mShaderFiles.clear(); + gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectV.glsl", GL_VERTEX_SHADER_ARB)); + gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/reflectionmipF.glsl", GL_FRAGMENT_SHADER_ARB)); + gReflectionMipProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + success = gReflectionMipProgram.createShader(NULL, NULL); + if (success) + { + gReflectionMipProgram.bind(); + gReflectionMipProgram.uniform1i(sScreenMap, 0); + gReflectionMipProgram.unbind(); + } + } + + if (success) + { + gRadianceGenProgram.mName = "Radiance Gen Shader"; + gRadianceGenProgram.mShaderFiles.clear(); + gRadianceGenProgram.mShaderFiles.push_back(make_pair("interface/radianceGenV.glsl", GL_VERTEX_SHADER_ARB)); + gRadianceGenProgram.mShaderFiles.push_back(make_pair("interface/radianceGenF.glsl", GL_FRAGMENT_SHADER_ARB)); + gRadianceGenProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + success = gRadianceGenProgram.createShader(NULL, NULL); + } + + if (success) + { + gIrradianceGenProgram.mName = "Irradiance Gen Shader"; + gIrradianceGenProgram.mShaderFiles.clear(); + gIrradianceGenProgram.mShaderFiles.push_back(make_pair("interface/irradianceGenV.glsl", GL_VERTEX_SHADER_ARB)); + gIrradianceGenProgram.mShaderFiles.push_back(make_pair("interface/irradianceGenF.glsl", GL_FRAGMENT_SHADER_ARB)); + gIrradianceGenProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + success = gIrradianceGenProgram.createShader(NULL, NULL); + } + if( !success ) { mShaderLevel[SHADER_INTERFACE] = 0; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 93bb29a355..ef49074959 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -49,7 +49,11 @@ public: void setShaders(); void unloadShaders(); S32 getShaderLevel(S32 type); - BOOL loadBasicShaders(); + + // loadBasicShaders in case of a failure returns + // name of a file error happened at, otherwise + // returns an empty string + std::string loadBasicShaders(); BOOL loadShadersEffects(); BOOL loadShadersDeferred(); BOOL loadShadersObject(); @@ -161,6 +165,9 @@ extern LLGLSLShader gOcclusionCubeProgram; extern LLGLSLShader gCustomAlphaProgram; extern LLGLSLShader gGlowCombineProgram; extern LLGLSLShader gSplatTextureRectProgram; +extern LLGLSLShader gReflectionMipProgram; +extern LLGLSLShader gRadianceGenProgram; +extern LLGLSLShader gIrradianceGenProgram; extern LLGLSLShader gGlowCombineFXAAProgram; extern LLGLSLShader gDebugProgram; extern LLGLSLShader gClipProgram; @@ -313,4 +320,6 @@ extern LLGLSLShader gNormalMapGenProgram; // Deferred materials shaders extern LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; extern LLGLSLShader gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2]; + +extern LLGLSLShader gDeferredPBROpaqueProgram; #endif diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 57d52ae9ee..796ff04a41 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -489,6 +489,7 @@ void send_viewer_stats(bool include_preferences) system["os"] = LLOSInfo::instance().getOSStringSimple(); system["cpu"] = gSysCPU.getCPUString(); system["address_size"] = ADDRESS_SIZE; + system["os_bitness"] = LLOSInfo::instance().getOSBitness(); unsigned char MACAddress[MAC_ADDRESS_BYTES]; LLUUID::getNodeID(MACAddress); std::string macAddressString = llformat("%02x-%02x-%02x-%02x-%02x-%02x", diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index e2de7ac825..7c860936a5 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -879,6 +879,7 @@ BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, case DAD_ANIMATION: case DAD_GESTURE: case DAD_MESH: + case DAD_MATERIAL: { supported = true; break; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 3584fffd44..0c23214b52 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -286,6 +286,13 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const U32 wid return tex; } +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLImageRaw* raw, FTType type, bool usemipmaps) +{ + LLViewerFetchedTexture* ret = new LLViewerFetchedTexture(raw, type, usemipmaps); + gTextureList.addImage(ret, TEX_LIST_STANDARD); + return ret; +} + LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( const LLUUID &image_id, FTType f_type, diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 8c41c4a6bc..5893f549d0 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -660,6 +660,8 @@ public: static LLPointer<LLViewerTexture> getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) ; static LLPointer<LLViewerTexture> getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ; + static LLViewerFetchedTexture* getFetchedTexture(const LLImageRaw* raw, FTType type, bool usemipmaps); + static LLViewerFetchedTexture* getFetchedTexture(const LLUUID &image_id, FTType f_type = FTT_DEFAULT, BOOL usemipmap = TRUE, diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 8faeb70553..1a766dd404 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1173,7 +1173,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); if (image.isNull()) { - image->setLastError("Couldn't open the image to be uploaded."); + LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL; return FALSE; } if (!image->load(filename)) diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index bd60c990b5..cc6523c23e 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -1,10 +1,10 @@ /** - * @file llviewertexturelinumimagest.h + * @file llviewertexturelist.h * @brief Object for managing the list of images within a region * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, 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 diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 15f20d1d34..e9815a7872 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -103,7 +103,6 @@ #include "llfilepicker.h" #include "llfirstuse.h" #include "llfloater.h" -#include "llfloaterbuildoptions.h" #include "llfloaterbuyland.h" #include "llfloatercamera.h" #include "llfloaterland.h" @@ -228,6 +227,7 @@ extern BOOL gDebugClicks; extern BOOL gDisplaySwapBuffers; extern BOOL gDepthDirty; extern BOOL gResizeScreenTexture; +extern BOOL gCubeSnapshot; LLViewerWindow *gViewerWindow = NULL; @@ -1900,7 +1900,7 @@ LLViewerWindow::LLViewerWindow(const Params& p) gSavedSettings.getBOOL("RenderVSyncEnable"), !gHeadlessClient, p.ignore_pixel_depth, - gSavedSettings.getBOOL("RenderDeferred") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled + 0); //don't use window level anti-aliasing if (NULL == mWindow) { @@ -2221,6 +2221,7 @@ void LLViewerWindow::initWorldUI() gStatusBar->setShape(status_bar_container->getLocalRect()); // sync bg color with menu bar gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() ); + // add InBack so that gStatusBar won't be drawn over menu status_bar_container->addChildInBack(gStatusBar); status_bar_container->setVisible(TRUE); @@ -3200,6 +3201,11 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) void LLViewerWindow::handleScrollHWheel(S32 clicks) { + if (LLAppViewer::instance()->quitRequested()) + { + return; + } + LLUI::getInstance()->resetMouseIdleTimer(); LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); @@ -3358,7 +3364,7 @@ void LLViewerWindow::updateUI() if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { gDebugRaycastFaceHit = -1; - gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, + gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, &gDebugRaycastFaceHit, &gDebugRaycastIntersection, &gDebugRaycastTexCoord, @@ -4182,13 +4188,16 @@ void LLViewerWindow::pickAsync( S32 x, BOOL pick_rigged, BOOL pick_unselectable) { - BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); - if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) - { - // build mode allows interaction with all transparent objects - // "Show Debug Alpha" means no object actually transparent - pick_transparent = TRUE; - } + // "Show Debug Alpha" means no object actually transparent + BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); + if (LLDrawPoolAlpha::sShowDebugAlpha) + { + pick_transparent = TRUE; + } + else if (in_build_mode && !gSavedSettings.getBOOL("SelectInvisibleObjects")) + { + pick_transparent = FALSE; + } LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, FALSE, TRUE, pick_unselectable, callback); schedulePick(pick_info); @@ -4246,10 +4255,10 @@ void LLViewerWindow::returnEmptyPicks() } // Performs the GL object/land pick. -LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_particle) +LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_particle, BOOL pick_unselectable) { BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); - if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) + if ((in_build_mode && gSavedSettings.getBOOL("SelectInvisibleObjects")) || LLDrawPoolAlpha::sShowDebugAlpha) { // build mode allows interaction with all transparent objects // "Show Debug Alpha" means no object actually transparent @@ -4295,6 +4304,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de S32 this_face, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, LLVector4a *intersection, LLVector2 *uv, @@ -4365,7 +4375,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de { if (this_object->isHUDAttachment()) // is a HUD object? { - if (this_object->lineSegmentIntersect(mh_start, mh_end, this_face, pick_transparent, pick_rigged, + if (this_object->lineSegmentIntersect(mh_start, mh_end, this_face, pick_transparent, pick_rigged, pick_unselectable, face_hit, intersection, uv, normal, tangent)) { found = this_object; @@ -4373,7 +4383,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de } else // is a world object { - if (this_object->lineSegmentIntersect(mw_start, mw_end, this_face, pick_transparent, pick_rigged, + if (this_object->lineSegmentIntersect(mw_start, mw_end, this_face, pick_transparent, pick_rigged, pick_unselectable, face_hit, intersection, uv, normal, tangent)) { found = this_object; @@ -4387,7 +4397,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de if (!found) // if not found in HUD, look in world: { - found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, + found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, pick_unselectable, face_hit, intersection, uv, normal, tangent); if (found && !pick_transparent) { @@ -4645,8 +4655,8 @@ void LLViewerWindow::saveImageNumbered(LLImageFormatted *image, BOOL force_picke else pick_type = LLFilePicker::FFSAVE_ALL; - (new LLFilePickerReplyThread(boost::bind(&LLViewerWindow::onDirectorySelected, this, _1, formatted_image, success_cb, failure_cb), pick_type, proposed_name, - boost::bind(&LLViewerWindow::onSelectionFailure, this, failure_cb)))->getFile(); + LLFilePickerReplyThread::startPicker(boost::bind(&LLViewerWindow::onDirectorySelected, this, _1, formatted_image, success_cb, failure_cb), pick_type, proposed_name, + boost::bind(&LLViewerWindow::onSelectionFailure, this, failure_cb)); } else { @@ -4914,8 +4924,8 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei U32 color_fmt = type == LLSnapshotModel::SNAPSHOT_TYPE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGBA; if (scratch_space.allocate(image_width, image_height, color_fmt, true, true)) { - original_width = gPipeline.mDeferredScreen.getWidth(); - original_height = gPipeline.mDeferredScreen.getHeight(); + original_width = gPipeline.mRT->deferredScreen.getWidth(); + original_height = gPipeline.mRT->deferredScreen.getHeight(); if (gPipeline.allocateScreenBuffer(image_width, image_height)) { @@ -4994,8 +5004,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear()); F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear()); - gObjectList.generatePickList(*LLViewerCamera::getInstance()); - // Subimages are in fact partial rendering of the final view. This happens when the final view is bigger than the screen. // In most common cases, scale_factor is 1 and there's no more than 1 iteration on x and y for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y) @@ -5158,6 +5166,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_height, const int num_render_passes) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; gDisplaySwapBuffers = FALSE; glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); @@ -5172,8 +5181,8 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_ LLPipeline::sShowHUDAttachments = FALSE; LLRect window_rect = getWorldViewRectRaw(); - S32 original_width = LLPipeline::sRenderDeferred ? gPipeline.mDeferredScreen.getWidth() : gViewerWindow->getWorldViewWidthRaw(); - S32 original_height = LLPipeline::sRenderDeferred ? gPipeline.mDeferredScreen.getHeight() : gViewerWindow->getWorldViewHeightRaw(); + S32 original_width = LLPipeline::sRenderDeferred ? gPipeline.mRT->deferredScreen.getWidth() : gViewerWindow->getWorldViewWidthRaw(); + S32 original_height = LLPipeline::sRenderDeferred ? gPipeline.mRT->deferredScreen.getHeight() : gViewerWindow->getWorldViewHeightRaw(); LLRenderTarget scratch_space; U32 color_fmt = GL_RGBA; @@ -5254,6 +5263,149 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_ return true; } +void display_cube_face(); + +BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render) +{ + // NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; + LL_PROFILE_GPU_ZONE("cubeSnapshot"); + llassert(LLPipeline::sRenderDeferred); + llassert(!gCubeSnapshot); //assert a snapshot isn't already in progress + + U32 res = LLRenderTarget::sCurResX; + + llassert(res <= gPipeline.mRT->deferredScreen.getWidth()); + llassert(res <= gPipeline.mRT->deferredScreen.getHeight()); + + // save current view/camera settings so we can restore them afterwards + S32 old_occlusion = LLPipeline::sUseOcclusion; + + // set new parameters specific to the 360 requirements + LLPipeline::sUseOcclusion = 0; + LLViewerCamera* camera = LLViewerCamera::getInstance(); + + LLViewerCamera saved_camera = LLViewerCamera::instance(); + glh::matrix4f saved_proj = get_current_projection(); + glh::matrix4f saved_mod = get_current_modelview(); + + // camera constants for the square, cube map capture image + camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV + camera->setView(F_PI_BY_TWO); + camera->yaw(0.0); + camera->setOrigin(origin); + camera->setNear(near_clip); + + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + U32 dynamic_render_types[] = { + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_CONTROL_AV, + LLPipeline::RENDER_TYPE_PARTICLES + }; + constexpr U32 dynamic_render_type_count = sizeof(dynamic_render_types) / sizeof(U32); + bool prev_dynamic_render_type[dynamic_render_type_count]; + + + if (!dynamic_render) + { + for (int i = 0; i < dynamic_render_type_count; ++i) + { + prev_dynamic_render_type[i] = gPipeline.hasRenderType(dynamic_render_types[i]); + if (prev_dynamic_render_type[i]) + { + gPipeline.toggleRenderType(dynamic_render_types[i]); + } + } + } + + BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE; + if (prev_draw_ui != false) + { + LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + + LLPipeline::sShowHUDAttachments = FALSE; + LLRect window_rect = getWorldViewRectRaw(); + + mWorldViewRectRaw.set(0, res, res, 0); + + // these are the 6 directions we will point the camera, see LLCubeMapArray::sTargets + LLVector3 look_dirs[6] = { + LLVector3(1, 0, 0), + LLVector3(-1, 0, 0), + LLVector3(0, 1, 0), + LLVector3(0, -1, 0), + LLVector3(0, 0, 1), + LLVector3(0, 0, -1) + }; + + LLVector3 look_upvecs[6] = { + LLVector3(0, -1, 0), + LLVector3(0, -1, 0), + LLVector3(0, 0, 1), + LLVector3(0, 0, -1), + LLVector3(0, -1, 0), + LLVector3(0, -1, 0) + }; + + // for each of six sides of cubemap + //for (int i = 0; i < 6; ++i) + int i = face; + { + // set up camera to look in each direction + camera->lookDir(look_dirs[i], look_upvecs[i]); + + // turning this flag off here prohibits the screen swap + // to present the new page to the viewer - this stops + // the black flash in between captures when the number + // of render passes is more than 1. We need to also + // set it here because code in LLViewerDisplay resets + // it to TRUE each time. + gDisplaySwapBuffers = FALSE; + + // actually render the scene + gCubeSnapshot = TRUE; + display_cube_face(); + gCubeSnapshot = FALSE; + } + + gDisplaySwapBuffers = TRUE; + + if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + if (prev_draw_ui != false) + { + LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI); + } + } + + if (!dynamic_render) + { + for (int i = 0; i < dynamic_render_type_count; ++i) + { + if (prev_dynamic_render_type[i]) + { + gPipeline.toggleRenderType(dynamic_render_types[i]); + } + } + } + + LLPipeline::sShowHUDAttachments = TRUE; + + gPipeline.resetDrawOrders(); + mWorldViewRectRaw = window_rect; + + // restore original view/camera/avatar settings settings + *camera = saved_camera; + set_current_modelview(saved_mod); + set_current_projection(saved_proj); + LLPipeline::sUseOcclusion = old_occlusion; + + // ==================================================== + return true; +} + void LLViewerWindow::destroyWindow() { if (mWindow) @@ -5923,7 +6075,7 @@ void LLPickInfo::fetchResults() } LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f, - NULL, -1, mPickTransparent, mPickRigged, &face_hit, + NULL, -1, mPickTransparent, mPickRigged, mPickUnselectable, &face_hit, &intersection, &uv, &normal, &tangent, &start, &end); mPickPt = mMousePt; @@ -6068,7 +6220,7 @@ void LLPickInfo::getSurfaceInfo() if (objectp) { if (gViewerWindow->cursorIntersect(ll_round((F32)mMousePt.mX), ll_round((F32)mMousePt.mY), 1024.f, - objectp, -1, mPickTransparent, mPickRigged, + objectp, -1, mPickTransparent, mPickRigged, mPickUnselectable, &mObjectFace, &intersection, &mSTCoords, diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 979a560508..387a2cb06f 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -68,6 +68,8 @@ class LLWindowListener; class LLViewerWindowListener; class LLVOPartGroup; class LLPopupView; +class LLCubeMap; +class LLCubeMapArray; #define PICK_HALF_WIDTH 5 #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1) @@ -360,6 +362,20 @@ public: BOOL simpleSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, const int num_render_passes); + + + // take a cubemap snapshot + // origin - vantage point to take the snapshot from + // cubearray - cubemap array for storing the results + // index - cube index in the array to use (cube index, not face-layer) + // face - which cube face to update + // near_clip - near clip setting to use + BOOL cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 index, S32 face, F32 near_clip, bool render_avatars); + + + // special implementation of simpleSnapshot for reflection maps + BOOL reflectionSnapshot(LLImageRaw* raw, S32 image_width, S32 image_height, const int num_render_passes); + BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL show_hud, BOOL do_rebuild, LLSnapshotModel::ESnapshotLayerType type); BOOL isSnapshotLocSet() const; void resetSnapshotLoc() const; @@ -389,7 +405,7 @@ public: BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, BOOL pick_unselectable = FALSE); - LLPickInfo pickImmediate(S32 x, S32 y, BOOL pick_transparent, BOOL pick_rigged = FALSE, BOOL pick_particle = FALSE); + LLPickInfo pickImmediate(S32 x, S32 y, BOOL pick_transparent, BOOL pick_rigged = FALSE, BOOL pick_particle = FALSE, BOOL pick_unselectable = TRUE); LLHUDIcon* cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth, LLVector4a* intersection); @@ -398,6 +414,7 @@ public: S32 this_face = -1, BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, LLVector4a *intersection = NULL, LLVector2 *uv = NULL, diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b8ebe92430..30e3d77d29 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1777,6 +1777,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& S32 face, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, @@ -1883,6 +1884,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector S32 face, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, @@ -1913,7 +1915,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector { LLViewerObject* attached_object = attachment_iter->get(); - if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) + if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, pick_unselectable, face_hit, &local_intersection, tex_coord, normal, tangent)) { local_end = local_intersection; if (intersection) @@ -4619,7 +4621,12 @@ bool LLVOAvatar::updateCharacter(LLAgent &agent) } else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED)) { - getOffObject(); + // If we are starting up, motion might be loading + LLMotion *motionp = mMotionController.findMotion(ANIM_AGENT_SIT_GROUND_CONSTRAINED); + if (!motionp || !mMotionController.isMotionLoading(motionp)) + { + getOffObject(); + } } //-------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 3c3decaad6..a085d773dc 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -164,6 +164,7 @@ public: S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, // which face was hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point @@ -174,6 +175,7 @@ public: S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, // which face was hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 9a41eedb54..d109b7b34f 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -758,7 +758,7 @@ void LLVOGrass::updateDrawable(BOOL force_damped) } // virtual -BOOL LLVOGrass::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, +BOOL LLVOGrass::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) { diff --git a/indra/newview/llvograss.h b/indra/newview/llvograss.h index 5634e048eb..63876dc099 100644 --- a/indra/newview/llvograss.h +++ b/indra/newview/llvograss.h @@ -79,6 +79,7 @@ public: S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, // which face was hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 068e8a131d..cb4315a774 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -485,6 +485,7 @@ BOOL LLVOPartGroup::lineSegmentIntersect(const LLVector4a& start, const LLVector S32 face, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, @@ -756,6 +757,7 @@ LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) : void LLParticlePartition::rebuildGeom(LLSpatialGroup* group) { LL_PROFILE_ZONE_SCOPED; + LL_PROFILE_GPU_ZONE("particle vbo"); if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY)) { return; diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h index 4e4d6e609d..a45d381dfa 100644 --- a/indra/newview/llvopartgroup.h +++ b/indra/newview/llvopartgroup.h @@ -74,6 +74,7 @@ public: S32 face, BOOL pick_transparent, BOOL pick_rigged, + BOOL pick_unselectable, S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index 01312d65cc..1aa00bc894 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -660,9 +660,7 @@ void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time) void LLVOSky::forceSkyUpdate() { mForceUpdate = TRUE; - - memset(&m_lastAtmosphericsVars, 0x00, sizeof(AtmosphericsVars)); - + m_lastAtmosphericsVars = {}; mCubeMapUpdateStage = -1; } diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index b0af565867..6b56eaeb4a 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -880,7 +880,7 @@ void LLVOSurfacePatch::getGeomSizesEast(const S32 stride, const S32 east_stride, } } -BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, +BOOL LLVOSurfacePatch::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) { diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h index 884dbb3be3..aed67162d1 100644 --- a/indra/newview/llvosurfacepatch.h +++ b/indra/newview/llvosurfacepatch.h @@ -85,6 +85,7 @@ public: S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, // which face was hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 493162b47b..e26791aa29 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -1170,7 +1170,7 @@ void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) mDrawable->setPositionGroup(pos); } -BOOL LLVOTree::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, +BOOL LLVOTree::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) { diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h index 93c22d2da3..996e970cf8 100644 --- a/indra/newview/llvotree.h +++ b/indra/newview/llvotree.h @@ -111,6 +111,7 @@ public: S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, // which face was hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index f7678f5f26..ad11fb3908 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -105,7 +105,7 @@ S32 LLVOVolume::mRenderComplexity_current = 0; LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL; LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL; -extern BOOL gGLDebugLoggingEnabled; +extern BOOL gCubeSnapshot; // Implementation class of LLMediaDataClientObject. See llmediadataclient.h class LLMediaDataClientObjectImpl : public LLMediaDataClientObject @@ -232,6 +232,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mMediaImplList.resize(getNumTEs()); mLastFetchedMediaVersion = -1; + mServerDrawableUpdateCount = 0; memset(&mIndexInTex, 0, sizeof(S32) * LLRender::NUM_VOLUME_TEXTURE_CHANNELS); mMDCImplCount = 0; mLastRiggingInfoLOD = -1; @@ -327,6 +328,9 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, LLColor4U color; const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA); + const bool previously_volume_changed = mVolumeChanged; + const bool previously_face_mapping_changed = mFaceMappingChanged; + const bool previously_color_changed = mColorChanged; // Do base class updates... U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); @@ -550,9 +554,31 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // ...and clean up any media impls cleanUpMediaImpls(); + if (( + (mVolumeChanged && !previously_volume_changed) || + (mFaceMappingChanged && !previously_face_mapping_changed) || + (mColorChanged && !previously_color_changed) + ) + && !mLODChanged) { + onDrawableUpdateFromServer(); + } + return retval; } +// Called when a volume, material, etc is updated by the server, possibly by a +// script. If this occurs too often for this object, mark it as active so that +// it doesn't disrupt the octree/render batches, thereby potentially causing a +// big performance penalty. +void LLVOVolume::onDrawableUpdateFromServer() +{ + constexpr U32 UPDATES_UNTIL_ACTIVE = 8; + ++mServerDrawableUpdateCount; + if (mDrawable && !mDrawable->isActive() && mServerDrawableUpdateCount > UPDATES_UNTIL_ACTIVE) + { + mDrawable->makeActive(); + } +} void LLVOVolume::animateTextures() { @@ -717,7 +743,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; // Update the pixel area of all faces - if (mDrawable.isNull()) + if (mDrawable.isNull() || gCubeSnapshot) { return; } @@ -982,7 +1008,12 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) // Add it to the pipeline mLightSet gPipeline.setLight(mDrawable, TRUE); } - + + if (isReflectionProbe()) + { + updateReflectionProbePtr(); + } + updateRadius(); bool force_update = true; // avoid non-alpha mDistance update being optimized away mDrawable->updateDistance(*LLViewerCamera::getInstance(), force_update); @@ -1670,7 +1701,7 @@ void LLVOVolume::regenFaces() } } -BOOL LLVOVolume::genBBoxes(BOOL force_global) +BOOL LLVOVolume::genBBoxes(BOOL force_global, BOOL should_update_octree_bounds) { LL_PROFILE_ZONE_SCOPED; BOOL res = TRUE; @@ -1746,20 +1777,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) } } - bool rigged = false; - - if (!isAnimatedObject()) - { - rigged = isRiggedMesh() && isAttachment(); - } - else - { - rigged = isRiggedMesh() && getControlAvatar() && getControlAvatar()->mPlaying; - } - if (any_valid_boxes) { - if (rebuild) + if (rebuild && should_update_octree_bounds) { //get the Avatar associated with this object if it's rigged LLVOAvatar* avatar = nullptr; @@ -1921,7 +1941,7 @@ void LLVOVolume::updateRelativeXform(bool force_identity) } } -bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) +bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled, BOOL &should_update_octree_bounds) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; bool regen_faces = false; @@ -1953,6 +1973,9 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) } compiled = TRUE; + // new_lod > old_lod breaks a feedback loop between LOD updates and + // bounding box updates. + should_update_octree_bounds = should_update_octree_bounds || mSculptChanged || new_lod > old_lod; sNumLODChanges += new_num_faces; if ((S32)getNumTEs() != getVolume()->getNumFaces()) @@ -2012,8 +2035,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) group->dirtyMesh(); } - BOOL compiled = FALSE; - updateRelativeXform(); if (mDrawable.isNull()) // Not sure why this is happening, but it is... @@ -2021,49 +2042,55 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) return TRUE; // No update to complete } + BOOL compiled = FALSE; + // This should be true in most cases, unless we're sure no octree update is + // needed. + BOOL should_update_octree_bounds = bool(getRiggedVolume()) || mDrawable->isState(LLDrawable::REBUILD_POSITION) || !mDrawable->getSpatialExtents()->isFinite3(); + if (mVolumeChanged || mFaceMappingChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); bool was_regen_faces = false; + should_update_octree_bounds = true; if (mVolumeChanged) { - was_regen_faces = lodOrSculptChanged(drawable, compiled); + was_regen_faces = lodOrSculptChanged(drawable, compiled, should_update_octree_bounds); drawable->setState(LLDrawable::REBUILD_VOLUME); } else if (mSculptChanged || mLODChanged || mColorChanged) { compiled = TRUE; - was_regen_faces = lodOrSculptChanged(drawable, compiled); + was_regen_faces = lodOrSculptChanged(drawable, compiled, should_update_octree_bounds); } if (!was_regen_faces) { regenFaces(); } - - genBBoxes(FALSE); } else if (mLODChanged || mSculptChanged || mColorChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); compiled = TRUE; - lodOrSculptChanged(drawable, compiled); + lodOrSculptChanged(drawable, compiled, should_update_octree_bounds); if(drawable->isState(LLDrawable::REBUILD_RIGGED | LLDrawable::RIGGED)) { updateRiggedVolume(false); } - genBBoxes(FALSE); } // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local else { compiled = TRUE; // All it did was move or we changed the texture coordinate offset - genBBoxes(FALSE); } + // Generate bounding boxes if needed, and update the object's size in the + // octree + genBBoxes(FALSE, should_update_octree_bounds); + // Update face flags updateFaceFlags(); @@ -2154,7 +2181,8 @@ void LLVOVolume::setNumTEs(const U8 num_tes) return ; } -//virtual + +//virtual void LLVOVolume::changeTEImage(S32 index, LLViewerTexture* imagep) { BOOL changed = (mTEImages[index] != imagep); @@ -3386,6 +3414,11 @@ F32 LLVOVolume::getSpotLightPriority() const void LLVOVolume::updateSpotLightPriority() { + if (gCubeSnapshot) + { + return; + } + F32 r = getLightRadius(); LLVector3 pos = mDrawable->getPositionAgent(); @@ -3488,6 +3521,129 @@ F32 LLVOVolume::getLightCutoff() const } } +BOOL LLVOVolume::isReflectionProbe() const +{ + return getParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE); +} + +void LLVOVolume::setIsReflectionProbe(BOOL is_probe) +{ + BOOL was_probe = isReflectionProbe(); + if (is_probe != was_probe) + { + if (is_probe) + { + setParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE, TRUE, true); + } + else + { + setParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE, FALSE, true); + } + } + + updateReflectionProbePtr(); +} + +void LLVOVolume::setReflectionProbeAmbiance(F32 ambiance) +{ + LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + if (param_block->getAmbiance() != ambiance) + { + param_block->setAmbiance(ambiance); + parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true); + } + } +} + +void LLVOVolume::setReflectionProbeNearClip(F32 near_clip) +{ + LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + if (param_block->getClipDistance() != near_clip) + { + param_block->setClipDistance(near_clip); + parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true); + } + } +} + +void LLVOVolume::setReflectionProbeIsBox(bool is_box) +{ + LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + if (param_block->getIsBox() != is_box) + { + param_block->setIsBox(is_box); + parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true); + } + } +} + +void LLVOVolume::setReflectionProbeIsDynamic(bool is_dynamic) +{ + LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + if (param_block->getIsDynamic() != is_dynamic) + { + param_block->setIsDynamic(is_dynamic); + parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true); + } + } +} + +F32 LLVOVolume::getReflectionProbeAmbiance() const +{ + const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + return param_block->getAmbiance(); + } + else + { + return 0.f; + } +} + +F32 LLVOVolume::getReflectionProbeNearClip() const +{ + const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + return param_block->getClipDistance(); + } + else + { + return 0.f; + } +} + +bool LLVOVolume::getReflectionProbeIsBox() const +{ + const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + return param_block->getIsBox(); + } + + return false; +} + +bool LLVOVolume::getReflectionProbeIsDynamic() const +{ + const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE); + if (param_block) + { + return param_block->getIsDynamic(); + } + + return false; +} + U32 LLVOVolume::getVolumeInterfaceID() const { if (mVolumeImpl) @@ -4373,6 +4529,23 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u gPipeline.setLight(mDrawable, is_light); } } + + updateReflectionProbePtr(); +} + +void LLVOVolume::updateReflectionProbePtr() +{ + if (isReflectionProbe()) + { + if (mReflectionProbe.isNull()) + { + mReflectionProbe = gPipeline.mReflectionMapManager.registerViewerObject(this); + } + } + else if (mReflectionProbe.notNull()) + { + mReflectionProbe = nullptr; + } } void LLVOVolume::setSelected(BOOL sel) @@ -4572,7 +4745,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, S32 *face_hitp, +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) { @@ -4583,6 +4756,14 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& return FALSE; } + if (!pick_unselectable) + { + if (!LLSelectMgr::instance().canSelectObject(this)) + { + return FALSE; + } + } + BOOL ret = FALSE; LLVolume* volume = getVolume(); @@ -5215,10 +5396,26 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LLViewerTexture* tex = facep->getTexture(); + U8 index = facep->getTextureIndex(); - LLMaterial* mat = facep->getTextureEntry()->getMaterialParams().get(); - LLMaterialID mat_id = facep->getTextureEntry()->getMaterialID(); + LLMaterial* mat = nullptr; + + LLUUID mat_id; + + LLGLTFMaterial* gltf_mat = facep->getTextureEntry()->getGLTFMaterial(); + if (gltf_mat != nullptr) + { + mat_id = gltf_mat->getHash(); // TODO: cache this hash + } + else + { + mat = facep->getTextureEntry()->getMaterialParams().get(); + if (mat) + { + mat_id = facep->getTextureEntry()->getMaterialID().asUUID(); + } + } bool batchable = false; @@ -5240,7 +5437,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0) { - if (mat || draw_vec[idx]->mMaterial) + if (mat || gltf_mat || draw_vec[idx]->mMaterial) { //can't batch textures when materials are present (yet) batchable = false; } @@ -5272,7 +5469,6 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && #endif - //draw_vec[idx]->mMaterial == mat && draw_vec[idx]->mMaterialID == mat_id && draw_vec[idx]->mFullbright == fullbright && draw_vec[idx]->mBump == bump && @@ -5329,11 +5525,22 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_info->mEnvIntensity = spec; draw_info->mSpecularMap = NULL; draw_info->mMaterial = mat; + draw_info->mGLTFMaterial = gltf_mat; draw_info->mShaderMask = shader_mask; draw_info->mAvatar = facep->mAvatar; draw_info->mSkinInfo = facep->mSkinInfo; - if (mat) + if (gltf_mat) + { + LLViewerObject* vobj = facep->getViewerObject(); + U8 te = facep->getTEOffset(); + + draw_info->mTexture = vobj->getGLTFAlbedoMap(te); + draw_info->mNormalMap = vobj->getGLTFNormalMap(te); + draw_info->mSpecularMap = vobj->getGLTFMetallicRoughnessMap(te); + draw_info->mEmissiveMap = vobj->getGLTFEmissiveMap(te); + } + else if (mat) { draw_info->mMaterialID = mat_id; @@ -5495,6 +5702,8 @@ static inline void add_face(T*** list, U32* count, T* face) void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + llassert(!gCubeSnapshot); + if (group->changeLOD()) { group->mLastUpdateDistance = group->mDistance; @@ -5672,6 +5881,20 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) continue; } + // HACK -- brute force this check every time a drawable gets rebuilt + vobj->updateTEMaterialTextures(i); +#if 0 +#if LL_RELEASE_WITH_DEBUG_INFO + const LLUUID pbr_id( "49c88210-7238-2a6b-70ac-92d4f35963cf" ); + const LLUUID obj_id( vobj->getID() ); + bool is_pbr = (obj_id == pbr_id); +#else + bool is_pbr = false; +#endif +#else + bool is_pbr = facep->getTextureEntry()->getGLTFMaterial() != nullptr; +#endif + //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render // batch, it will recover its vertex buffer reference from the spatial group facep->setVertexBuffer(NULL); @@ -5737,6 +5960,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); U32 type = gPipeline.getPoolTypeFromTE(te, tex); + + if (is_pbr) + { + type = LLDrawPool::POOL_PBR_OPAQUE; + } + else if (type != LLDrawPool::POOL_ALPHA && force_simple) { type = LLDrawPool::POOL_SIMPLE; @@ -5801,28 +6030,39 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (gPipeline.canUseWindLightShadersOnObjects() && LLPipeline::sRenderBump) { - if (LLPipeline::sRenderDeferred && te->getMaterialParams().notNull() && !te->getMaterialID().isNull()) + LLGLTFMaterial* gltf_mat = te->getGLTFMaterial(); + + if (LLPipeline::sRenderDeferred && + (gltf_mat != nullptr || (te->getMaterialParams().notNull() && !te->getMaterialID().isNull()))) { - LLMaterial* mat = te->getMaterialParams().get(); - if (mat->getNormalID().notNull()) - { - if (mat->getSpecularID().notNull()) - { //has normal and specular maps (needs texcoord1, texcoord2, and tangent) - add_face(sNormSpecFaces, normspec_count, facep); - } - else - { //has normal map (needs texcoord1 and tangent) - add_face(sNormFaces, norm_count, facep); - } - } - else if (mat->getSpecularID().notNull()) - { //has specular map but no normal map, needs texcoord2 - add_face(sSpecFaces, spec_count, facep); - } - else - { //has neither specular map nor normal map, only needs texcoord0 - add_face(sSimpleFaces, simple_count, facep); - } + if (gltf_mat != nullptr) + { + // all gltf materials have all vertex attributes for now + add_face(sNormSpecFaces, normspec_count, facep); + } + else + { + LLMaterial* mat = te->getMaterialParams().get(); + if (mat->getNormalID().notNull()) + { + if (mat->getSpecularID().notNull()) + { //has normal and specular maps (needs texcoord1, texcoord2, and tangent) + add_face(sNormSpecFaces, normspec_count, facep); + } + else + { //has normal map (needs texcoord1 and tangent) + add_face(sNormFaces, norm_count, facep); + } + } + else if (mat->getSpecularID().notNull()) + { //has specular map but no normal map, needs texcoord2 + add_face(sSpecFaces, spec_count, facep); + } + else + { //has neither specular map nor normal map, only needs texcoord0 + add_face(sSimpleFaces, simple_count, facep); + } + } } else if (te->getBumpmap()) { //needs normal + tangent @@ -6509,15 +6749,24 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE; - LLMaterial* mat = te->getMaterialParams().get(); + LLGLTFMaterial* gltf_mat = te->getGLTFMaterial(); - bool can_be_shiny = true; - if (mat) - { - U8 mode = mat->getDiffuseAlphaMode(); - can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE || - mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE; - } + LLMaterial* mat = nullptr; + bool can_be_shiny = false; + + // ignore traditional material if GLTF material is present + if (gltf_mat == nullptr) + { + mat = te->getMaterialParams().get(); + + can_be_shiny = true; + if (mat) + { + U8 mode = mat->getDiffuseAlphaMode(); + can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE || + mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE; + } + } F32 te_alpha = te->getColor().mV[3]; bool use_legacy_bump = te->getBumpmap() && (te->getBumpmap() < 18) && (!mat || mat->getNormalID().isNull()); @@ -6526,10 +6775,15 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace is_alpha = (is_alpha || transparent) ? TRUE : FALSE; - if (mat && LLPipeline::sRenderDeferred && !hud_group) + if ((gltf_mat || mat) && LLPipeline::sRenderDeferred && !hud_group) { bool material_pass = false; + if (gltf_mat) + { // all other parameters ignored if gltf material is present + registerFace(group, facep, LLRenderPass::PASS_PBR_OPAQUE); + } + else // do NOT use 'fullbright' for this logic or you risk sending // things without normals down the materials pipeline and will // render poorly if not crash NORSPEC-240,314 diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 4cb7a5481c..391351c13e 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -114,49 +114,50 @@ public: }; public: - LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); - /*virtual*/ void markDead(); // Override (and call through to parent) to clean up media references + LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); + void markDead() override; // Override (and call through to parent) to clean up media references - /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); + LLDrawable* createDrawable(LLPipeline *pipeline) override; void deleteFaces(); void animateTextures(); BOOL isVisible() const ; - /*virtual*/ BOOL isActive() const; - /*virtual*/ BOOL isAttachment() const; - /*virtual*/ BOOL isRootEdit() const; // overridden for sake of attachments treating themselves as a root object - /*virtual*/ BOOL isHUDAttachment() const; + BOOL isActive() const override; + BOOL isAttachment() const override; + BOOL isRootEdit() const override; // overridden for sake of attachments treating themselves as a root object + BOOL isHUDAttachment() const override; void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); - /*virtual*/ BOOL setParent(LLViewerObject* parent); - S32 getLOD() const { return mLOD; } + /*virtual*/ BOOL setParent(LLViewerObject* parent) override; + S32 getLOD() const override { return mLOD; } void setNoLOD() { mLOD = NO_LOD; mLODChanged = TRUE; } bool isNoLOD() const { return NO_LOD == mLOD; } - const LLVector3 getPivotPositionAgent() const; + const LLVector3 getPivotPositionAgent() const override; const LLMatrix4& getRelativeXform() const { return mRelativeXform; } const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } - /*virtual*/ const LLMatrix4 getRenderMatrix() const; + /*virtual*/ const LLMatrix4 getRenderMatrix() const override; typedef std::map<LLUUID, S32> texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; - /*virtual*/ F32 getEstTrianglesMax() const; - /*virtual*/ F32 getEstTrianglesStreamingCost() const; - /* virtual*/ F32 getStreamingCost() const; - /*virtual*/ bool getCostData(LLMeshCostData& costs) const; + /*virtual*/ F32 getEstTrianglesMax() const override; + /*virtual*/ F32 getEstTrianglesStreamingCost() const override; + /* virtual*/ F32 getStreamingCost() const override; + /*virtual*/ bool getCostData(LLMeshCostData& costs) const override; - /*virtual*/ U32 getTriangleCount(S32* vcount = NULL) const; - /*virtual*/ U32 getHighLODTriangleCount(); + /*virtual*/ U32 getTriangleCount(S32* vcount = NULL) const override; + /*virtual*/ U32 getHighLODTriangleCount() override; /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, BOOL pick_rigged = FALSE, + BOOL pick_unselectable = TRUE, S32* face_hit = NULL, // which face was hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point LLVector4a* normal = NULL, // return the surface normal at the intersection point LLVector4a* tangent = NULL // return the surface tangent at the intersection point - ); + ) override; LLVector3 agentPositionToVolume(const LLVector3& pos) const; LLVector3 agentDirectionToVolume(const LLVector3& dir) const; @@ -166,55 +167,58 @@ public: BOOL getVolumeChanged() const { return mVolumeChanged; } - /*virtual*/ F32 getRadius() const { return mVObjRadius; }; - const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; + F32 getVObjRadius() const override { return mVObjRadius; }; + const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const override; - void markForUpdate(BOOL priority); + void markForUpdate(BOOL priority) override; void markForUnload() { LLViewerObject::markForUnload(TRUE); mVolumeChanged = TRUE; } - void faceMappingChanged() { mFaceMappingChanged=TRUE; }; + void faceMappingChanged() override { mFaceMappingChanged=TRUE; } - /*virtual*/ void onShift(const LLVector4a &shift_vector); // Called when the drawable shifts + /*virtual*/ void onShift(const LLVector4a &shift_vector) override; // Called when the drawable shifts - /*virtual*/ void parameterChanged(U16 param_type, bool local_origin); - /*virtual*/ void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin); + /*virtual*/ void parameterChanged(U16 param_type, bool local_origin) override; + /*virtual*/ void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin) override; + + // update mReflectionProbe based on isReflectionProbe() + void updateReflectionProbePtr(); /*virtual*/ U32 processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, U32 block_num, const EObjectUpdateType update_type, - LLDataPacker *dp); - - /*virtual*/ void setSelected(BOOL sel); - /*virtual*/ BOOL setDrawableParent(LLDrawable* parentp); - - /*virtual*/ void setScale(const LLVector3 &scale, BOOL damped); - - /*virtual*/ void changeTEImage(S32 index, LLViewerTexture* new_image) ; - /*virtual*/ void setNumTEs(const U8 num_tes); - /*virtual*/ void setTEImage(const U8 te, LLViewerTexture *imagep); - /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); - /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color); - /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color); - /*virtual*/ S32 setTEBumpmap(const U8 te, const U8 bump); - /*virtual*/ S32 setTEShiny(const U8 te, const U8 shiny); - /*virtual*/ S32 setTEFullbright(const U8 te, const U8 fullbright); - /*virtual*/ S32 setTEBumpShinyFullbright(const U8 te, const U8 bump); - /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags); - /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); - /*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID); + LLDataPacker *dp) override; + + /*virtual*/ void setSelected(BOOL sel) override; + /*virtual*/ BOOL setDrawableParent(LLDrawable* parentp) override; + + /*virtual*/ void setScale(const LLVector3 &scale, BOOL damped) override; + + /*virtual*/ void changeTEImage(S32 index, LLViewerTexture* new_image) override; + /*virtual*/ void setNumTEs(const U8 num_tes) override; + /*virtual*/ void setTEImage(const U8 te, LLViewerTexture *imagep) override; + /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid) override; + /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color) override; + /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color) override; + /*virtual*/ S32 setTEBumpmap(const U8 te, const U8 bump) override; + /*virtual*/ S32 setTEShiny(const U8 te, const U8 shiny) override; + /*virtual*/ S32 setTEFullbright(const U8 te, const U8 fullbright) override; + /*virtual*/ S32 setTEBumpShinyFullbright(const U8 te, const U8 bump) override; + /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags) override; + /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow) override; + /*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID) override; static void setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID& pMaterialID, const LLMaterialPtr pMaterialParams, U32 te); - /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams); - /*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t); - /*virtual*/ S32 setTEScaleS(const U8 te, const F32 s); - /*virtual*/ S32 setTEScaleT(const U8 te, const F32 t); - /*virtual*/ S32 setTETexGen(const U8 te, const U8 texgen); - /*virtual*/ S32 setTEMediaTexGen(const U8 te, const U8 media); - /*virtual*/ BOOL setMaterial(const U8 material); + /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) override; + /*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t) override; + /*virtual*/ S32 setTEScaleS(const U8 te, const F32 s) override; + /*virtual*/ S32 setTEScaleT(const U8 te, const F32 t) override; + /*virtual*/ S32 setTETexGen(const U8 te, const U8 texgen) override; + /*virtual*/ S32 setTEMediaTexGen(const U8 te, const U8 media) override; + /*virtual*/ BOOL setMaterial(const U8 material) override; void setTexture(const S32 face); S32 getIndexInTex(U32 ch) const {return mIndexInTex[ch];} - /*virtual*/ BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false); + /*virtual*/ BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false) override; void updateSculptTexture(); void setIndexInTex(U32 ch, S32 index) { mIndexInTex[ch] = index ;} void sculpt(); @@ -223,21 +227,21 @@ public: void* user_data, S32 status, LLExtStat ext_status); void updateRelativeXform(bool force_identity = false); - /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); - /*virtual*/ void updateFaceSize(S32 idx); - /*virtual*/ BOOL updateLOD(); - void updateRadius(); - /*virtual*/ void updateTextures(); + /*virtual*/ BOOL updateGeometry(LLDrawable *drawable) override; + /*virtual*/ void updateFaceSize(S32 idx) override; + /*virtual*/ BOOL updateLOD() override; + void updateRadius() override; + /*virtual*/ void updateTextures() override; void updateTextureVirtualSize(bool forced = false); void updateFaceFlags(); void regenFaces(); - BOOL genBBoxes(BOOL force_global); + BOOL genBBoxes(BOOL force_global, BOOL should_update_octree_bounds = TRUE); void preRebuild(); - virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); - virtual F32 getBinRadius(); + virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max) override; + virtual F32 getBinRadius() override; - virtual U32 getPartitionType() const; + virtual U32 getPartitionType() const override; // For Lights void setIsLight(BOOL is_light); @@ -280,14 +284,27 @@ public: F32 getLightRadius() const; F32 getLightFalloff(const F32 fudge_factor = 1.f) const; F32 getLightCutoff() const; - + + // Reflection Probes + void setIsReflectionProbe(BOOL is_probe); + void setReflectionProbeAmbiance(F32 ambiance); + void setReflectionProbeNearClip(F32 near_clip); + void setReflectionProbeIsBox(bool is_box); + void setReflectionProbeIsDynamic(bool is_dynamic); + + BOOL isReflectionProbe() const override; + F32 getReflectionProbeAmbiance() const; + F32 getReflectionProbeNearClip() const; + bool getReflectionProbeIsBox() const; + bool getReflectionProbeIsDynamic() const; + // Flexible Objects U32 getVolumeInterfaceID() const; - virtual BOOL isFlexible() const; - virtual BOOL isSculpted() const; - virtual BOOL isMesh() const; - virtual BOOL isRiggedMesh() const; - virtual BOOL hasLightTexture() const; + virtual BOOL isFlexible() const override; + virtual BOOL isSculpted() const override; + virtual BOOL isMesh() const override; + virtual BOOL isRiggedMesh() const override; + virtual BOOL hasLightTexture() const override; BOOL isVolumeGlobal() const; @@ -304,12 +321,12 @@ public: void onSetExtendedMeshFlags(U32 flags); void setExtendedMeshFlags(U32 flags); bool canBeAnimatedObject() const; - bool isAnimatedObject() const; - virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); - virtual void afterReparent(); + bool isAnimatedObject() const override; + virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) override; + virtual void afterReparent() override; //virtual - void updateRiggingInfo(); + void updateRiggingInfo() override; S32 mLastRiggingInfoLOD; // Functions that deal with media, or media navigation @@ -386,13 +403,14 @@ protected: static S32 mRenderComplexity_last; static S32 mRenderComplexity_current; + void onDrawableUpdateFromServer(); void requestMediaDataUpdate(bool isNew); void cleanUpMediaImpls(); void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ; void removeMediaImpl(S32 texture_index) ; private: - bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled); + bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled, BOOL &shouldUpdateOctreeBounds); public: @@ -424,6 +442,7 @@ private: LLPointer<LLViewerFetchedTexture> mLightTexture; media_list_t mMediaImplList; S32 mLastFetchedMediaVersion; // as fetched from the server, starts as -1 + U32 mServerDrawableUpdateCount; S32 mIndexInTex[LLRender::NUM_VOLUME_TEXTURE_CHANNELS]; S32 mMDCImplCount; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 8abb49fba8..8837038d02 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -820,7 +820,7 @@ void LLWorld::updateNetStats() void LLWorld::printPacketsLost() { - LL_INFOS() << "Simulators:" << LL_ENDL; + LL_INFOS() << "Simulators:" << LL_ENDL; LL_INFOS() << "----------" << LL_ENDL; LLCircuitData *cdp = NULL; @@ -855,6 +855,7 @@ F32 LLWorld::getLandFarClip() const void LLWorld::setLandFarClip(const F32 far_clip) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; static S32 const rwidth = (S32)REGION_WIDTH_U32; S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth; S32 const n2 = (llceil(far_clip) - 1) / rwidth; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index d4e667bcc6..91d276c8df 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -227,6 +227,7 @@ extern S32 gBoxFrame; //extern BOOL gHideSelectedObjects; extern BOOL gDisplaySwapBuffers; extern BOOL gDebugGL; +extern BOOL gCubeSnapshot; bool gAvatarBacklight = false; @@ -280,29 +281,33 @@ static LLStaticHashedString sKern("kern"); static LLStaticHashedString sKernScale("kern_scale"); //---------------------------------------- -std::string gPoolNames[] = +#if 0 +std::string gPoolNames[LLDrawPool::NUM_POOL_TYPES] = { // Correspond to LLDrawpool enum render type - "NONE", - "POOL_SIMPLE", - "POOL_GROUND", - "POOL_FULLBRIGHT", - "POOL_BUMP", - "POOL_MATERIALS", - "POOL_TERRAIN," - "POOL_SKY", - "POOL_WL_SKY", - "POOL_TREE", - "POOL_ALPHA_MASK", - "POOL_FULLBRIGHT_ALPHA_MASK", - "POOL_GRASS", - "POOL_INVISIBLE", - "POOL_AVATAR", - "POOL_VOIDWATER", - "POOL_WATER", - "POOL_GLOW", - "POOL_ALPHA" + "NONE" + , "POOL_SIMPLE" + , "POOL_GROUND" + , "POOL_FULLBRIGHT" + , "POOL_BUMP" + , "POOL_MATERIALS" + , "POOL_TERRAIN" + , "POOL_SKY" + , "POOL_WL_SKY" + , "POOL_TREE" + , "POOL_ALPHA_MASK" + , "POOL_FULLBRIGHT_ALPHA_MASK" + , "POOL_GRASS" + , "POOL_INVISIBLE" + , "POOL_AVATAR" + , "POOL_CONTROL_AV" // Animesh + , "POOL_VOIDWATER" + , "POOL_WATER" + , "POOL_GLOW" + , "POOL_ALPHA" + , "POOL_PBR_OPAQUE" }; +#endif void drawBox(const LLVector4a& c, const LLVector4a& r); void drawBoxOutline(const LLVector3& pos, const LLVector3& size); @@ -350,6 +355,7 @@ bool LLPipeline::sRenderFrameTest = false; bool LLPipeline::sRenderAttachedLights = true; bool LLPipeline::sRenderAttachedParticles = true; bool LLPipeline::sRenderDeferred = false; +bool LLPipeline::sRenderPBR = false; S32 LLPipeline::sVisibleLightCount = 0; bool LLPipeline::sRenderingHUDs; F32 LLPipeline::sDistortionWaterClipPlaneMargin = 1.0125f; @@ -366,8 +372,12 @@ void validate_framebuffer_object(); // for_impostor -- whether or not these render targets are for an impostor (if true, avoids implicit sRGB conversions) bool addDeferredAttachments(LLRenderTarget& target, bool for_impostor = false) { - return target.addColorAttachment(for_impostor ? GL_RGBA : GL_SRGB8_ALPHA8) && //specular - target.addColorAttachment(GL_RGB10_A2); //normal+z + bool pbr = gSavedSettings.getBOOL("RenderPBR"); + bool valid = true + && target.addColorAttachment(for_impostor ? GL_RGBA : GL_SRGB8_ALPHA8) // frag-data[1] specular or PBR sRGB Emissive + && target.addColorAttachment(GL_RGB10_A2) // frag_data[2] normal+z+fogmask, See: class1\deferred\materialF.glsl & softenlight + && (pbr ? target.addColorAttachment(GL_RGBA) : true); // frag_data[3] PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl + return valid; } LLPipeline::LLPipeline() : @@ -405,9 +415,7 @@ LLPipeline::LLPipeline() : mWLSkyPool(NULL), mLightMask(0), mLightMovingMask(0), - mLightingDetail(0), - mScreenWidth(0), - mScreenHeight(0) + mLightingDetail(0) { mNoiseMap = 0; mTrueNoiseMap = 0; @@ -437,10 +445,12 @@ void LLPipeline::init() LL_WARNS() << "Begin pipeline initialization" << LL_ENDL; // TODO: Remove after testing refreshCachedSettings(); + mRT = &mMainRT; + gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity"); gOctreeMinSize = gSavedSettings.getF32("OctreeMinimumNodeSize"); sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD"); - sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); + sRenderBump = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("RenderObjectBump"); sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); @@ -464,6 +474,7 @@ void LLPipeline::init() getPool(LLDrawPool::POOL_BUMP); getPool(LLDrawPool::POOL_MATERIALS); getPool(LLDrawPool::POOL_GLOW); + getPool(LLDrawPool::POOL_PBR_OPAQUE); resetFrameStats(); @@ -541,8 +552,9 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("RenderAvatarMaxNonImpostors"); connectRefreshCachedSettingsSafe("RenderDelayVBUpdate"); connectRefreshCachedSettingsSafe("UseOcclusion"); - connectRefreshCachedSettingsSafe("WindLightUseAtmosShaders"); - connectRefreshCachedSettingsSafe("RenderDeferred"); + // DEPRECATED -- connectRefreshCachedSettingsSafe("WindLightUseAtmosShaders"); + // DEPRECATED -- connectRefreshCachedSettingsSafe("RenderDeferred"); + connectRefreshCachedSettingsSafe("RenderPBR"); connectRefreshCachedSettingsSafe("RenderDeferredSunWash"); connectRefreshCachedSettingsSafe("RenderFSAASamples"); connectRefreshCachedSettingsSafe("RenderResolutionDivisor"); @@ -736,8 +748,9 @@ void LLPipeline::requestResizeShadowTexture() void LLPipeline::resizeShadowTexture() { - releaseShadowTargets(); - allocateShadowBuffer(mScreenWidth, mScreenHeight); + releaseSunShadowTargets(); + releaseSpotShadowTargets(); + allocateShadowBuffer(mRT->width, mRT->height); gResizeShadowTexture = FALSE; } @@ -748,10 +761,11 @@ void LLPipeline::resizeScreenTexture() GLuint resX = gViewerWindow->getWorldViewWidthRaw(); GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - if (gResizeScreenTexture || (resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) + if (gResizeScreenTexture || (resX != mRT->screen.getWidth()) || (resY != mRT->screen.getHeight())) { releaseScreenBuffers(); - releaseShadowTargets(); + releaseSunShadowTargets(); + releaseSpotShadowTargets(); allocateScreenBuffer(resX,resY); gResizeScreenTexture = FALSE; } @@ -771,42 +785,16 @@ void LLPipeline::allocatePhysicsBuffer() bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY) { - refreshCachedSettings(); - - bool save_settings = sRenderDeferred; - if (save_settings) - { - // Set this flag in case we crash while resizing window or allocating space for deferred rendering targets - gSavedSettings.setBOOL("RenderInitError", TRUE); - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - } - + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; eFBOStatus ret = doAllocateScreenBuffer(resX, resY); - if (save_settings) - { - // don't disable shaders on next session - gSavedSettings.setBOOL("RenderInitError", FALSE); - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - } - - if (ret == FBO_FAILURE) - { //FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled - //NOTE: if the session closes successfully after this call, deferred rendering will be - // disabled on future sessions - if (LLPipeline::sRenderDeferred) - { - gSavedSettings.setBOOL("RenderDeferred", FALSE); - LLPipeline::refreshCachedSettings(); - } - } - return ret == FBO_SUCCESS_FULLRES; } LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; // try to allocate screen buffers at requested resolution and samples // - on failure, shrink number of samples and try again // - if not multisampled, shrink resolution and try again (favor X resolution over Y) @@ -860,11 +848,20 @@ LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY) bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) { - refreshCachedSettings(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + if (mRT == &mMainRT) + { // hacky -- allocate auxillary buffer + gCubeSnapshot = TRUE; + mRT = &mAuxillaryRT; + U32 res = LL_REFLECTION_PROBE_RESOLUTION * 2; + allocateScreenBuffer(res, res, samples); + mRT = &mMainRT; + gCubeSnapshot = FALSE; + } // remember these dimensions - mScreenWidth = resX; - mScreenHeight = resY; + mRT->width = resX; + mRT->height = resY; U32 res_mod = RenderResolutionDivisor; @@ -876,7 +873,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (RenderUIBuffer) { - if (!mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) + if (!mRT->uiScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) { return false; } @@ -890,10 +887,10 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) const U32 occlusion_divisor = 3; //allocate deferred rendering color buffers - if (!mDeferredScreen.allocate(resX, resY, GL_SRGB8_ALPHA8, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; - if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; - if (!mOcclusionDepth.allocate(resX/occlusion_divisor, resY/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; - if (!addDeferredAttachments(mDeferredScreen)) return false; + if (!mRT->deferredScreen.allocate(resX, resY, GL_SRGB8_ALPHA8, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (!mRT->deferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (!mRT->occlusionDepth.allocate(resX/occlusion_divisor, resY/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (!addDeferredAttachments(mRT->deferredScreen)) return false; GLuint screenFormat = GL_RGBA16; if (gGLManager.mIsAMD) @@ -906,23 +903,23 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) screenFormat = GL_RGBA16F_ARB; } - if (!mScreen.allocate(resX, resY, screenFormat, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; + if (!mRT->screen.allocate(resX, resY, screenFormat, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false; if (samples > 0) { - if (!mFXAABuffer.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false; + if (!mRT->fxaaBuffer.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false; } else { - mFXAABuffer.release(); + mRT->fxaaBuffer.release(); } if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0) - { //only need mDeferredLight for shadows OR ssao OR dof OR fxaa - if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + { //only need mRT->deferredLight for shadows OR ssao OR dof OR fxaa + if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; } else { - mDeferredLight.release(); + mRT->deferredLight.release(); } allocateShadowBuffer(resX, resY); @@ -935,22 +932,23 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) } else { - mDeferredLight.release(); + mRT->deferredLight.release(); - releaseShadowTargets(); + releaseSunShadowTargets(); + releaseSpotShadowTargets(); - mFXAABuffer.release(); - mScreen.release(); - mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first - mDeferredDepth.release(); - mOcclusionDepth.release(); + mRT->fxaaBuffer.release(); + mRT->screen.release(); + mRT->deferredScreen.release(); //make sure to release any render targets that share a depth buffer with mRT->deferredScreen first + mRT->deferredDepth.release(); + mRT->occlusionDepth.release(); - if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + if (!mRT->screen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; } if (LLPipeline::sRenderDeferred) { //share depth buffer between deferred targets - mDeferredScreen.shareDepthBuffer(mScreen); + mRT->deferredScreen.shareDepthBuffer(mRT->screen); } gGL.getTexUnit(0)->disable(); @@ -965,68 +963,67 @@ inline U32 BlurHappySize(U32 x, F32 scale) { return U32( x * scale + 16.0f) & ~0 bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY) { - refreshCachedSettings(); - - if (LLPipeline::sRenderDeferred) - { - S32 shadow_detail = RenderShadowDetail; + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + if (LLPipeline::sRenderDeferred) + { + S32 shadow_detail = RenderShadowDetail; - const U32 occlusion_divisor = 3; + const U32 occlusion_divisor = 3; - F32 scale = llmax(0.f,RenderShadowResolutionScale); - U32 sun_shadow_map_width = BlurHappySize(resX, scale); - U32 sun_shadow_map_height = BlurHappySize(resY, scale); + F32 scale = llmax(0.f, RenderShadowResolutionScale); + U32 sun_shadow_map_width = BlurHappySize(resX, scale); + U32 sun_shadow_map_height = BlurHappySize(resY, scale); - if (shadow_detail > 0) - { //allocate 4 sun shadow maps - for (U32 i = 0; i < 4; i++) - { - if (!mShadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) + if (shadow_detail > 0) + { //allocate 4 sun shadow maps + for (U32 i = 0; i < 4; i++) + { + if (!mRT->shadow[i].allocate(sun_shadow_map_width, sun_shadow_map_height, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) { return false; } - if (!mShadowOcclusion[i].allocate(sun_shadow_map_width/occlusion_divisor, sun_shadow_map_height/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) + if (!mRT->shadowOcclusion[i].allocate(sun_shadow_map_width / occlusion_divisor, sun_shadow_map_height / occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) { return false; } - } - } - else - { - for (U32 i = 0; i < 4; i++) - { - releaseShadowTarget(i); - } - } - - U32 width = (U32) (resX*scale); - U32 height = width; + } + } + else + { + for (U32 i = 0; i < 4; i++) + { + releaseSunShadowTarget(i); + } + } - if (shadow_detail > 1) - { //allocate two spot shadow maps - U32 spot_shadow_map_width = width; - U32 spot_shadow_map_height = height; - for (U32 i = 4; i < 6; i++) - { - if (!mShadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, TRUE, FALSE)) - { - return false; - } - if (!mShadowOcclusion[i].allocate(spot_shadow_map_width/occlusion_divisor, height/occlusion_divisor, 0, TRUE, FALSE)) - { - return false; - } - } + if (!gCubeSnapshot) // hack to not allocate spot shadow maps during ReflectionMapManager init + { + U32 width = (U32)(resX * scale); + U32 height = width; + + if (shadow_detail > 1) + { //allocate two spot shadow maps + U32 spot_shadow_map_width = width; + U32 spot_shadow_map_height = height; + for (U32 i = 0; i < 2; i++) + { + if (!mSpotShadow[i].allocate(spot_shadow_map_width, spot_shadow_map_height, 0, TRUE, FALSE)) + { + return false; + } + if (!mSpotShadowOcclusion[i].allocate(spot_shadow_map_width / occlusion_divisor, height / occlusion_divisor, 0, TRUE, FALSE)) + { + return false; + } + } + } + else + { + releaseSpotShadowTargets(); + } } - else - { - for (U32 i = 4; i < 6; i++) - { - releaseShadowTarget(i); - } - } - } + } return true; } @@ -1040,7 +1037,7 @@ void LLPipeline::updateRenderTransparentWater() //static void LLPipeline::updateRenderBump() { - sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); + sRenderBump = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("RenderObjectBump"); } // static @@ -1050,13 +1047,14 @@ void LLPipeline::updateRenderDeferred() RenderDeferred && LLRenderTarget::sUseFBO && LLPipeline::sRenderBump && - WindLightUseAtmosShaders && - (bool) LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); + WindLightUseAtmosShaders; + sRenderPBR = sRenderDeferred && gSavedSettings.getBOOL("RenderPBR"); } // static void LLPipeline::refreshCachedSettings() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred"); LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred"); LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip"); @@ -1070,8 +1068,8 @@ void LLPipeline::refreshCachedSettings() && gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) ? 2 : 0; - WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); - RenderDeferred = gSavedSettings.getBOOL("RenderDeferred"); + WindLightUseAtmosShaders = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("WindLightUseAtmosShaders"); + RenderDeferred = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("RenderDeferred"); RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash"); RenderFSAASamples = gSavedSettings.getU32("RenderFSAASamples"); RenderResolutionDivisor = gSavedSettings.getU32("RenderResolutionDivisor"); @@ -1198,36 +1196,50 @@ void LLPipeline::releaseLUTBuffers() void LLPipeline::releaseShadowBuffers() { - releaseShadowTargets(); + releaseSunShadowTargets(); + releaseSpotShadowTargets(); } void LLPipeline::releaseScreenBuffers() { - mUIScreen.release(); - mScreen.release(); - mFXAABuffer.release(); + mRT->uiScreen.release(); + mRT->screen.release(); + mRT->fxaaBuffer.release(); mPhysicsDisplay.release(); - mDeferredScreen.release(); - mDeferredDepth.release(); - mDeferredLight.release(); - mOcclusionDepth.release(); + mRT->deferredScreen.release(); + mRT->deferredDepth.release(); + mRT->deferredLight.release(); + mRT->occlusionDepth.release(); } -void LLPipeline::releaseShadowTarget(U32 index) +void LLPipeline::releaseSunShadowTarget(U32 index) { - mShadow[index].release(); - mShadowOcclusion[index].release(); + llassert(index < 4); + mRT->shadow[index].release(); + mRT->shadowOcclusion[index].release(); } -void LLPipeline::releaseShadowTargets() +void LLPipeline::releaseSunShadowTargets() { - for (U32 i = 0; i < 6; i++) + for (U32 i = 0; i < 4; i++) { - releaseShadowTarget(i); + releaseSunShadowTarget(i); } } +void LLPipeline::releaseSpotShadowTargets() +{ + if (!gCubeSnapshot) // hack to avoid freeing spot shadows during ReflectionMapManager init + { + for (U32 i = 0; i < 2; i++) + { + mSpotShadow[i].release(); + mSpotShadowOcclusion[i].release(); + } + } +} + void LLPipeline::createGLBuffers() { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; @@ -1260,8 +1272,8 @@ void LLPipeline::createGLBuffers() } allocateScreenBuffer(resX, resY); - mScreenWidth = 0; - mScreenHeight = 0; + mRT->width = 0; + mRT->height = 0; if (sRenderDeferred) { @@ -1601,6 +1613,10 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) poolp = mWLSkyPool; break; + case LLDrawPool::POOL_PBR_OPAQUE: + poolp = mPBROpaquePool; + break; + default: llassert(0); LL_ERRS() << "Invalid Pool Type in LLPipeline::findPool() type=" << type << LL_ENDL; @@ -1642,6 +1658,7 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* ima } LLMaterial* mat = te->getMaterialParams().get(); + LLGLTFMaterial* gltf_mat = te->getGLTFMaterial(); bool color_alpha = te->getColor().mV[3] < 0.999f; bool alpha = color_alpha; @@ -1675,6 +1692,10 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* ima { return LLDrawPool::POOL_BUMP; } + else if (gltf_mat && !alpha) + { + return LLDrawPool::POOL_PBR_OPAQUE; + } else if (mat && !alpha) { return LLDrawPool::POOL_MATERIALS; @@ -2032,6 +2053,7 @@ void LLPipeline::updateMove() //static F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera) { + llassert(!gCubeSnapshot); // shouldn't be doing ANY of this during cube snap shots LLVector3 lookAt = center - camera.getOrigin(); F32 dist = lookAt.length(); @@ -2357,11 +2379,11 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* pla { if (LLPipeline::sRenderDeferred && can_use_occlusion) { - mOcclusionDepth.bindTarget(); + mRT->occlusionDepth.bindTarget(); } else { - mScreen.bindTarget(); + mRT->screen.bindTarget(); } } @@ -2483,11 +2505,11 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* pla { if (LLPipeline::sRenderDeferred && can_use_occlusion) { - mOcclusionDepth.flush(); + mRT->occlusionDepth.flush(); } else { - mScreen.flush(); + mRT->screen.flush(); } } } @@ -2501,7 +2523,7 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) group->setVisible(); - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot) { group->updateDistance(camera); } @@ -2607,6 +2629,8 @@ void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& d void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + llassert(!gCubeSnapshot); downsampleDepthBuffer(source, dest, scratch_space); dest.bindTarget(); doOcclusion(camera); @@ -2616,6 +2640,7 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT void LLPipeline::doOcclusion(LLCamera& camera) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + LL_PROFILE_GPU_ZONE("doOcclusion"); if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && (sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck)) { @@ -2849,7 +2874,7 @@ void LLPipeline::rebuildPriorityGroups() void LLPipeline::rebuildGroups() { - if (mGroupQ2.empty()) + if (mGroupQ2.empty() || gCubeSnapshot) { return; } @@ -2899,6 +2924,10 @@ void LLPipeline::updateGeom(F32 max_dtime) LLPointer<LLDrawable> drawablep; LL_RECORD_BLOCK_TIME(FTM_GEO_UPDATE); + if (gCubeSnapshot) + { + return; + } assertInitialized(); @@ -3138,6 +3167,8 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) } } + mReflectionMapManager.shift(offseta); + LLHUDText::shiftAll(offset); LLHUDNameTag::shiftAll(offset); @@ -3318,7 +3349,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } } - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot) { LLSpatialGroup* last_group = NULL; BOOL fov_changed = LLViewerCamera::getInstance()->isDefaultFOVChanged(); @@ -3400,7 +3431,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) stateSort(drawablep, camera); } - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot) { //avoid redundant stateSort calls group->mLastUpdateDistance = group->mDistance; } @@ -3469,7 +3500,7 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) } } - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot) { //if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here { @@ -3738,6 +3769,7 @@ void LLPipeline::touchTextures(LLDrawInfo* info) touchTexture(info->mTexture, info->mVSize); touchTexture(info->mSpecularMap, info->mVSize); touchTexture(info->mNormalMap, info->mVSize); + touchTexture(info->mEmissiveMap, info->mVSize); } void LLPipeline::postSort(LLCamera& camera) @@ -3747,21 +3779,26 @@ void LLPipeline::postSort(LLCamera& camera) assertInitialized(); LL_PUSH_CALLSTACKS(); - //rebuild drawable geometry - for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (!sUseOcclusion || - !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - group->rebuildGeom(); - } - } - LL_PUSH_CALLSTACKS(); - //rebuild groups - sCull->assertDrawMapsEmpty(); - rebuildPriorityGroups(); + if (!gCubeSnapshot) + { + //rebuild drawable geometry + for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) + { + LLSpatialGroup* group = *i; + if (!sUseOcclusion || + !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + { + group->rebuildGeom(); + } + } + LL_PUSH_CALLSTACKS(); + //rebuild groups + sCull->assertDrawMapsEmpty(); + + rebuildPriorityGroups(); + } + LL_PUSH_CALLSTACKS(); @@ -3777,7 +3814,7 @@ void LLPipeline::postSort(LLCamera& camera) continue; } - if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY)) + if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY) && !gCubeSnapshot) { //no way this group is going to be drawable without a rebuild group->rebuildGeom(); } @@ -3817,7 +3854,7 @@ void LLPipeline::postSort(LLCamera& camera) LLDrawInfo* info = *k; sCull->pushDrawInfo(j->first, info); - if (!sShadowRender && !sReflectionRender) + if (!sShadowRender && !sReflectionRender && !gCubeSnapshot) { touchTextures(info); addTrianglesDrawn(info->mCount, info->mDrawMode); @@ -3832,7 +3869,7 @@ void LLPipeline::postSort(LLCamera& camera) if (alpha != group->mDrawMap.end()) { //store alpha groups for sorting LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); - if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) + if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot) { if (bridge) { @@ -3965,7 +4002,7 @@ void LLPipeline::postSort(LLCamera& camera) } LL_PUSH_CALLSTACKS(); // If managing your telehub, draw beacons at telehub and currently selected spawnpoint. - if (LLFloaterTelehub::renderBeacons()) + if (LLFloaterTelehub::renderBeacons() && !sShadowRender) { LLFloaterTelehub::addBeacons(); } @@ -4288,7 +4325,7 @@ U32 LLPipeline::sCurRenderPoolType = 0 ; void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); - + LL_PROFILE_GPU_ZONE("renderGeom"); assertInitialized(); F32 saved_modelview[16]; @@ -4463,7 +4500,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) gGL.loadMatrix(gGLModelView); if (occlude) - { + { // catch uncommon condition where pools at drawpool grass and later are disabled occlude = false; gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -4538,14 +4575,10 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) void LLPipeline::renderGeomDeferred(LLCamera& camera) { LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); + LL_PROFILE_GPU_ZONE("renderGeomDeferred"); + { - // SL-15709 -- NOTE: Tracy only allows one ZoneScoped per function. - // Solutions are: - // 1. Use a new scope - // 2. Use named zones - // 3. Use transient zones LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS); LLGLEnable cull(GL_CULL_FACE); @@ -4566,6 +4599,12 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) LLGLState::checkStates(); LLGLState::checkTextureChannels(); + if (LLViewerShaderMgr::instance()->mShaderLevel[LLViewerShaderMgr::SHADER_DEFERRED] > 1) + { + //update reflection probe uniform + mReflectionMapManager.updateUniforms(); + } + U32 cur_type = 0; gGL.setColorMask(true, true); @@ -4637,6 +4676,8 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS); + LL_PROFILE_GPU_ZONE("renderGeomPostDeferred"); + U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -4659,11 +4700,12 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion) if (occlude && cur_type >= LLDrawPool::POOL_GRASS) { + llassert(!gCubeSnapshot); // never do occlusion culling on cube snapshots occlude = false; gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); LLGLSLShader::bindNoShader(); - doOcclusion(camera, mScreen, mOcclusionDepth, &mDeferredDepth); + doOcclusion(camera, mRT->screen, mRT->occlusionDepth, &mRT->deferredDepth); gGL.setColorMask(true, false); } @@ -4732,6 +4774,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion) void LLPipeline::renderGeomShadow(LLCamera& camera) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + LL_PROFILE_GPU_ZONE("renderGeomShadow"); U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -5186,7 +5229,6 @@ void LLPipeline::renderDebug() glPointSize(1.f); } - // Debug stuff. for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -5240,6 +5282,12 @@ void LLPipeline::renderDebug() visible_selected_groups.clear(); + //draw reflection probes and links between them + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_REFLECTION_PROBES) && !hud_only) + { + mReflectionMapManager.renderDebug(); + } + gUIProgram.bind(); if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST) && !hud_only) @@ -5728,6 +5776,18 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) } break; + case LLDrawPool::POOL_PBR_OPAQUE: + if( mPBROpaquePool ) + { + llassert(0); + LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate PBR Opaque Pool" << LL_ENDL; + } + else + { + mPBROpaquePool = new_poolp; + } + break; + default: llassert(0); LL_WARNS() << "Invalid Pool Type in LLPipeline::addPool()" << LL_ENDL; @@ -5844,6 +5904,11 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) mGroundPool = NULL; break; + case LLDrawPool::POOL_PBR_OPAQUE: + llassert( poolp == mPBROpaquePool ); + mPBROpaquePool = NULL; + break; + default: llassert(0); LL_WARNS() << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << LL_ENDL; @@ -5960,6 +6025,7 @@ void LLPipeline::setupAvatarLights(bool for_edit) static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; F32 inten = light->getLightIntensity(); if (inten < .001f) { @@ -5983,9 +6049,10 @@ static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_ void LLPipeline::calcNearbyLights(LLCamera& camera) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; assertInitialized(); - if (LLPipeline::sReflectionRender) + if (LLPipeline::sReflectionRender || gCubeSnapshot) { return; } @@ -6168,6 +6235,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) void LLPipeline::setupHWLights(LLDrawPool* pool) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; assertInitialized(); LLEnvironment& environment = LLEnvironment::instance(); @@ -6729,15 +6797,6 @@ void LLPipeline::toggleRenderType(U32 type) //static void LLPipeline::toggleRenderTypeControl(U32 type) { - U32 bit = (1<<type); - if (gPipeline.hasRenderType(type)) - { - LL_INFOS() << "Toggling render type mask " << std::hex << bit << " off" << std::dec << LL_ENDL; - } - else - { - LL_INFOS() << "Toggling render type mask " << std::hex << bit << " on" << std::dec << LL_ENDL; - } gPipeline.toggleRenderType(type); } @@ -6983,7 +7042,7 @@ LLVOPartGroup* LLPipeline::lineSegmentIntersectParticle(const LLVector4a& start, LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_PARTICLE); if (part && hasRenderType(part->mDrawableType)) { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, TRUE, FALSE, face_hit, &position, NULL, NULL, NULL); + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, TRUE, FALSE, TRUE, face_hit, &position, NULL, NULL, NULL); if (hit) { drawable = hit; @@ -7011,6 +7070,7 @@ LLVOPartGroup* LLPipeline::lineSegmentIntersectParticle(const LLVector4a& start, LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, const LLVector4a& end, bool pick_transparent, bool pick_rigged, + bool pick_unselectable, S32* face_hit, LLVector4a* intersection, // return the intersection point LLVector2* tex_coord, // return the texture coordinates of the intersection point @@ -7044,7 +7104,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, LLSpatialPartition* part = region->getSpatialPartition(j); if (part && hasRenderType(part->mDrawableType)) { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, face_hit, &position, tex_coord, normal, tangent); + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, face_hit, &position, tex_coord, normal, tangent); if (hit) { drawable = hit; @@ -7101,7 +7161,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_AVATAR); if (part && hasRenderType(part->mDrawableType)) { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, face_hit, &position, tex_coord, normal, tangent); + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, face_hit, &position, tex_coord, normal, tangent); if (hit) { LLVector4a delta; @@ -7189,7 +7249,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector4a& start, c LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD); if (part) { - LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, FALSE, face_hit, intersection, tex_coord, normal, tangent); + LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, FALSE, TRUE, face_hit, intersection, tex_coord, normal, tangent); if (hit) { drawable = hit; @@ -7490,9 +7550,11 @@ void LLPipeline::renderFinalize() } LLVector2 tc1(0, 0); - LLVector2 tc2((F32) mScreen.getWidth() * 2, (F32) mScreen.getHeight() * 2); + LLVector2 tc2((F32) mRT->screen.getWidth() * 2, (F32) mRT->screen.getHeight() * 2); LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM); + LL_PROFILE_GPU_ZONE("renderFinalize"); + gGL.color4f(1, 1, 1, 1); LLGLDepthTest depth(GL_FALSE); LLGLDisable blend(GL_BLEND); @@ -7514,6 +7576,7 @@ void LLPipeline::renderFinalize() if (sRenderGlow) { + LL_PROFILE_GPU_ZONE("glow"); mGlow[2].bindTarget(); mGlow[2].clear(); @@ -7538,7 +7601,7 @@ void LLPipeline::renderFinalize() gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - mScreen.bindTexture(0, 0, LLTexUnit::TFO_POINT); + mRT->screen.bindTexture(0, 0, LLTexUnit::TFO_POINT); gGL.color4f(1, 1, 1, 1); gPipeline.enableLightsFullbright(); @@ -7554,7 +7617,7 @@ void LLPipeline::renderFinalize() gGL.end(); - gGL.getTexUnit(0)->unbind(mScreen.getUsage()); + gGL.getTexUnit(0)->unbind(mRT->screen.getUsage()); mGlow[2].flush(); @@ -7632,7 +7695,7 @@ void LLPipeline::renderFinalize() gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - tc2.setVec((F32) mScreen.getWidth(), (F32) mScreen.getHeight()); + tc2.setVec((F32) mRT->screen.getWidth(), (F32) mRT->screen.getHeight()); gGL.flush(); @@ -7640,17 +7703,18 @@ void LLPipeline::renderFinalize() if (LLPipeline::sRenderDeferred) { - bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() && (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && - RenderDepthOfField; + RenderDepthOfField && + !gCubeSnapshot; - bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete(); + bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete(); gViewerWindow->setup3DViewport(); if (dof_enabled) { + LL_PROFILE_GPU_ZONE("dof"); LLGLSLShader *shader = &gDeferredPostProgram; LLGLDisable blend(GL_BLEND); @@ -7686,7 +7750,7 @@ void LLPipeline::renderFinalize() LLVector4a result; result.clear(); - gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, NULL, &result); + gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, NULL, &result); focus_point.set(result.getF32ptr()); } @@ -7735,7 +7799,7 @@ void LLPipeline::renderFinalize() const F32 default_fov = CameraFieldOfView * F_PI / 180.f; - // F32 aspect_ratio = (F32) mScreen.getWidth()/(F32)mScreen.getHeight(); + // F32 aspect_ratio = (F32) mRT->screen.getWidth()/(F32)mRT->screen.getHeight(); F32 dv = 2.f * default_focal_length * tanf(default_fov / 2.f); @@ -7755,15 +7819,15 @@ void LLPipeline::renderFinalize() F32 magnification = focal_length / (subject_distance - focal_length); { // build diffuse+bloom+CoF - mDeferredLight.bindTarget(); + mRT->deferredLight.bindTarget(); shader = &gDeferredCoFProgram; bindDeferredShader(*shader); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); if (channel > -1) { - mScreen.bindTexture(0, channel); + mRT->screen.bindTexture(0, channel); } shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance / 1000.f); @@ -7786,23 +7850,23 @@ void LLPipeline::renderFinalize() gGL.end(); unbindDeferredShader(*shader); - mDeferredLight.flush(); + mRT->deferredLight.flush(); } - U32 dof_width = (U32)(mScreen.getWidth() * CameraDoFResScale); - U32 dof_height = (U32)(mScreen.getHeight() * CameraDoFResScale); + U32 dof_width = (U32)(mRT->screen.getWidth() * CameraDoFResScale); + U32 dof_height = (U32)(mRT->screen.getHeight() * CameraDoFResScale); { // perform DoF sampling at half-res (preserve alpha channel) - mScreen.bindTarget(); + mRT->screen.bindTarget(); glViewport(0, 0, dof_width, dof_height); gGL.setColorMask(true, false); shader = &gDeferredPostProgram; bindDeferredShader(*shader); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); if (channel > -1) { - mDeferredLight.bindTexture(0, channel); + mRT->deferredLight.bindTexture(0, channel); } shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); @@ -7821,15 +7885,15 @@ void LLPipeline::renderFinalize() gGL.end(); unbindDeferredShader(*shader); - mScreen.flush(); + mRT->screen.flush(); gGL.setColorMask(true, true); } { // combine result based on alpha if (multisample) { - mDeferredLight.bindTarget(); - glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); + mRT->deferredLight.bindTarget(); + glViewport(0, 0, mRT->deferredScreen.getWidth(), mRT->deferredScreen.getHeight()); } else { @@ -7843,10 +7907,10 @@ void LLPipeline::renderFinalize() shader = &gDeferredDoFCombineProgram; bindDeferredShader(*shader); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); if (channel > -1) { - mScreen.bindTexture(0, channel); + mRT->screen.bindTexture(0, channel); } shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); @@ -7870,24 +7934,25 @@ void LLPipeline::renderFinalize() if (multisample) { - mDeferredLight.flush(); + mRT->deferredLight.flush(); } } } else { + LL_PROFILE_GPU_ZONE("no dof"); if (multisample) { - mDeferredLight.bindTarget(); + mRT->deferredLight.bindTarget(); } LLGLSLShader *shader = &gDeferredPostNoDoFProgram; bindDeferredShader(*shader); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); if (channel > -1) { - mScreen.bindTexture(0, channel); + mRT->screen.bindTexture(0, channel); } gGL.begin(LLRender::TRIANGLE_STRIP); @@ -7906,17 +7971,18 @@ void LLPipeline::renderFinalize() if (multisample) { - mDeferredLight.flush(); + mRT->deferredLight.flush(); } } if (multisample) { + LL_PROFILE_GPU_ZONE("aa"); // bake out texture2D with RGBL for FXAA shader - mFXAABuffer.bindTarget(); + mRT->fxaaBuffer.bindTarget(); - S32 width = mScreen.getWidth(); - S32 height = mScreen.getHeight(); + S32 width = mRT->screen.getWidth(); + S32 height = mRT->screen.getHeight(); glViewport(0, 0, width, height); LLGLSLShader *shader = &gGlowCombineFXAAProgram; @@ -7924,10 +7990,10 @@ void LLPipeline::renderFinalize() shader->bind(); shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); if (channel > -1) { - mDeferredLight.bindTexture(0, channel); + mRT->deferredLight.bindTexture(0, channel); } gGL.begin(LLRender::TRIANGLE_STRIP); @@ -7938,18 +8004,18 @@ void LLPipeline::renderFinalize() gGL.flush(); - shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); shader->unbind(); - mFXAABuffer.flush(); + mRT->fxaaBuffer.flush(); shader = &gFXAAProgram; shader->bind(); - channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mFXAABuffer.getUsage()); + channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mRT->fxaaBuffer.getUsage()); if (channel > -1) { - mFXAABuffer.bindTexture(0, channel, LLTexUnit::TFO_BILINEAR); + mRT->fxaaBuffer.bindTexture(0, channel, LLTexUnit::TFO_BILINEAR); } gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; @@ -7958,8 +8024,8 @@ void LLPipeline::renderFinalize() gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - F32 scale_x = (F32) width / mFXAABuffer.getWidth(); - F32 scale_y = (F32) height / mFXAABuffer.getHeight(); + F32 scale_x = (F32) width / mRT->fxaaBuffer.getWidth(); + F32 scale_y = (F32) height / mRT->fxaaBuffer.getHeight(); shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y); shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f / width * scale_x, 1.f / height * scale_y); shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f / width * scale_x, -0.5f / height * scale_y, @@ -8010,7 +8076,7 @@ void LLPipeline::renderFinalize() gGlowCombineProgram.bind(); gGL.getTexUnit(0)->bind(&mGlow[1]); - gGL.getTexUnit(1)->bind(&mScreen); + gGL.getTexUnit(1)->bind(&mRT->screen); LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); @@ -8053,10 +8119,10 @@ void LLPipeline::renderFinalize() gSplatTextureRectProgram.unbind(); } - if (LLRenderTarget::sUseFBO) - { // copy depth buffer from mScreen to framebuffer - LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), 0, 0, - mScreen.getWidth(), mScreen.getHeight(), + if (LLRenderTarget::sUseFBO && !gCubeSnapshot) + { // copy depth buffer from mRT->screen to framebuffer + LLRenderTarget::copyContentsToFramebuffer(mRT->screen, 0, 0, mRT->screen.getWidth(), mRT->screen.getHeight(), 0, 0, + mRT->screen.getWidth(), mRT->screen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); } @@ -8074,31 +8140,39 @@ void LLPipeline::renderFinalize() void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; - - LLRenderTarget* deferred_target = &mDeferredScreen; - LLRenderTarget* deferred_depth_target = &mDeferredDepth; - LLRenderTarget* deferred_light_target = &mDeferredLight; + LL_PROFILE_GPU_ZONE("bindDeferredShader"); + LLRenderTarget* deferred_target = &mRT->deferredScreen; + LLRenderTarget* deferred_depth_target = &mRT->deferredDepth; + LLRenderTarget* deferred_light_target = &mRT->deferredLight; shader.bind(); S32 channel = 0; channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, deferred_target->getUsage()); if (channel > -1) { - deferred_target->bindTexture(0,channel, LLTexUnit::TFO_POINT); + deferred_target->bindTexture(0,channel, LLTexUnit::TFO_POINT); // frag_data[0] } + // NOTE: PBR sRGB Emissive -- See: C++: addDeferredAttachments(), GLSL: pbropaqueF.glsl channel = shader.enableTexture(LLShaderMgr::DEFERRED_SPECULAR, deferred_target->getUsage()); if (channel > -1) { - deferred_target->bindTexture(1, channel, LLTexUnit::TFO_POINT); + deferred_target->bindTexture(1, channel, LLTexUnit::TFO_POINT); // frag_data[1] } channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, deferred_target->getUsage()); if (channel > -1) { - deferred_target->bindTexture(2, channel, LLTexUnit::TFO_POINT); + deferred_target->bindTexture(2, channel, LLTexUnit::TFO_POINT); // frag_data[2] } + // NOTE: PBR linear packed Occlusion, Roughness, Metal -- See: C++: addDeferredAttachments(), GLSL: pbropaqueF.glsl + channel = shader.enableTexture(LLShaderMgr::DEFERRED_EMISSIVE, deferred_target->getUsage()); + if (channel > -1) + { + deferred_target->bindTexture(3, channel, LLTexUnit::TFO_POINT); // frag_data[3] + } + channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_depth_target->getUsage()); if (channel > -1) { @@ -8159,7 +8233,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ for (U32 i = 0; i < 4; i++) { - LLRenderTarget* shadow_target = getShadowTarget(i); + LLRenderTarget* shadow_target = getSunShadowTarget(i); if (shadow_target) { channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_TEXTURE); @@ -8167,7 +8241,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ if (channel > -1) { stop_glerror(); - gGL.getTexUnit(channel)->bind(getShadowTarget(i), TRUE); + gGL.getTexUnit(channel)->bind(getSunShadowTarget(i), TRUE); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_ANISOTROPIC); gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); stop_glerror(); @@ -8179,27 +8253,27 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ } } - for (U32 i = 4; i < 6; i++) - { - channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i); - stop_glerror(); - if (channel > -1) - { - stop_glerror(); - LLRenderTarget* shadow_target = getShadowTarget(i); - if (shadow_target) - { - gGL.getTexUnit(channel)->bind(shadow_target, TRUE); - gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_ANISOTROPIC); - gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); - stop_glerror(); - } - } - } + for (U32 i = 4; i < 6; i++) + { + channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0 + i); + stop_glerror(); + if (channel > -1) + { + stop_glerror(); + LLRenderTarget* shadow_target = getSpotShadowTarget(i-4); + if (shadow_target) + { + gGL.getTexUnit(channel)->bind(shadow_target, TRUE); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + stop_glerror(); + } + } + } stop_glerror(); @@ -8226,16 +8300,19 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ { cube_map->enable(channel); cube_map->bind(); - F32* m = gGLModelView; - - F32 mat[] = { m[0], m[1], m[2], - m[4], m[5], m[6], - m[8], m[9], m[10] }; - - shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat); } + + F32* m = gGLModelView; + + F32 mat[] = { m[0], m[1], m[2], + m[4], m[5], m[6], + m[8], m[9], m[10] }; + + shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat); } + bindReflectionProbes(shader); + if (gAtmosphere) { // bind precomputed textures necessary for calculating sun and sky luminance @@ -8264,7 +8341,14 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ } } - shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV); + /*if (gCubeSnapshot) + { // we only really care about the first two values, but the shader needs increasing separation between clip planes + shader.uniform4f(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1.f, 64.f, 128.f, 256.f); + } + else*/ + { + shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV); + } shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash); shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise); shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize); @@ -8299,8 +8383,8 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV); shader.uniform3fv(LLShaderMgr::DEFERRED_MOON_DIR, 1, mTransformedMoonDir.mV); - shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mShadow[0].getWidth(), mShadow[0].getHeight()); - shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mShadow[4].getWidth(), mShadow[4].getHeight()); + shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mRT->shadow[0].getWidth(), mRT->shadow[0].getHeight()); + shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mSpotShadow[0].getWidth(), mSpotShadow[0].getHeight()); shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff); shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff); @@ -8336,14 +8420,15 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f) void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + LL_PROFILE_GPU_ZONE("renderDeferredLighting"); if (!sCull) { return; } - LLRenderTarget *deferred_target = &mDeferredScreen; - LLRenderTarget *deferred_depth_target = &mDeferredDepth; - LLRenderTarget *deferred_light_target = &mDeferredLight; + LLRenderTarget *deferred_target = &mRT->deferredScreen; + LLRenderTarget *deferred_depth_target = &mRT->deferredDepth; + LLRenderTarget *deferred_light_target = &mRT->deferredLight; { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED); @@ -8410,6 +8495,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) if (RenderDeferredSSAO || RenderShadowDetail > 0) { + LL_PROFILE_GPU_ZONE("sun program"); deferred_light_target->bindTarget(); { // paint shadow/SSAO light map (direct lighting lightmap) LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - sun shadow"); @@ -8457,66 +8543,79 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) } if (RenderDeferredSSAO) - { // soften direct lighting lightmap - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow"); - // blur lightmap - screen_target->bindTarget(); - glClearColor(1, 1, 1, 1); - screen_target->clear(GL_COLOR_BUFFER_BIT); - glClearColor(0, 0, 0, 0); - - bindDeferredShader(gDeferredBlurLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - LLVector3 go = RenderShadowGaussian; - const U32 kern_length = 4; - F32 blur_size = RenderShadowBlurSize; - F32 dist_factor = RenderShadowBlurDistFactor; - - // sample symmetrically with the middle sample falling exactly on 0.0 - F32 x = 0.f; - - LLVector3 gauss[32]; // xweight, yweight, offset - - for (U32 i = 0; i < kern_length; i++) - { - gauss[i].mV[0] = llgaussian(x, go.mV[0]); - gauss[i].mV[1] = llgaussian(x, go.mV[1]); - gauss[i].mV[2] = x; - x += 1.f; + { + /*if (gCubeSnapshot) + { // SSAO and shadows disabled in reflection maps + deferred_light_target->bindTarget(); + glClearColor(1, 1, 1, 1); + deferred_light_target->clear(); + glClearColor(0, 0, 0, 0); + deferred_light_target->flush(); } + else*/ + { + // soften direct lighting lightmap + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow"); + LL_PROFILE_GPU_ZONE("soften shadow"); + // blur lightmap + screen_target->bindTarget(); + glClearColor(1, 1, 1, 1); + screen_target->clear(GL_COLOR_BUFFER_BIT); + glClearColor(0, 0, 0, 0); - gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f); - gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); - gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV); - gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f)); + bindDeferredShader(gDeferredBlurLightProgram); + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + LLVector3 go = RenderShadowGaussian; + const U32 kern_length = 4; + F32 blur_size = RenderShadowBlurSize; + F32 dist_factor = RenderShadowBlurDistFactor; - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } + // sample symmetrically with the middle sample falling exactly on 0.0 + F32 x = 0.f; - screen_target->flush(); - unbindDeferredShader(gDeferredBlurLightProgram); + LLVector3 gauss[32]; // xweight, yweight, offset - bindDeferredShader(gDeferredBlurLightProgram, screen_target); + for (U32 i = 0; i < kern_length; i++) + { + gauss[i].mV[0] = llgaussian(x, go.mV[0]); + gauss[i].mV[1] = llgaussian(x, go.mV[1]); + gauss[i].mV[2] = x; + x += 1.f; + } - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - deferred_light_target->bindTarget(); + gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f); + gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); + gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV); + gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f)); - gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f); + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); + screen_target->flush(); + unbindDeferredShader(gDeferredBlurLightProgram); + + bindDeferredShader(gDeferredBlurLightProgram, screen_target); + + mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + deferred_light_target->bindTarget(); + + gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f); + + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + stop_glerror(); + mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } + deferred_light_target->flush(); + unbindDeferredShader(gDeferredBlurLightProgram); } - deferred_light_target->flush(); - unbindDeferredShader(gDeferredBlurLightProgram); } stop_glerror(); @@ -8537,12 +8636,19 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram; LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - atmospherics"); + LL_PROFILE_GPU_ZONE("atmospherics"); bindDeferredShader(soften_shader); LLEnvironment &environment = LLEnvironment::instance(); soften_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); soften_shader.uniform4fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV); + if(LLPipeline::sRenderPBR) + { + LLVector3 cameraAtAxis = LLViewerCamera::getInstance()->getAtAxis(); + soften_shader.uniform3fv(LLShaderMgr::DEFERRED_VIEW_DIR, 1, cameraAtAxis.mV); + } + { LLGLDepthTest depth(GL_FALSE); LLGLDisable blend(GL_BLEND); @@ -8583,7 +8689,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) gPipeline.popRenderTypeMask(); } - bool render_local = RenderLocalLights; + bool render_local = RenderLocalLights; // && !gCubeSnapshot; if (render_local) { @@ -8592,9 +8698,12 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) LLDrawable::drawable_list_t spot_lights; LLDrawable::drawable_list_t fullscreen_spot_lights; - for (U32 i = 0; i < 2; i++) + if (!gCubeSnapshot) { - mTargetShadowSpotLight[i] = NULL; + for (U32 i = 0; i < 2; i++) + { + mTargetShadowSpotLight[i] = NULL; + } } std::list<LLVector4> light_colors; @@ -8603,6 +8712,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - local lights"); + LL_PROFILE_GPU_ZONE("local lights"); bindDeferredShader(gDeferredLightProgram); if (mCubeVB.isNull()) @@ -8709,6 +8819,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) if (!spot_lights.empty()) { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - projectors"); + LL_PROFILE_GPU_ZONE("projectors"); LLGLDepthTest depth(GL_TRUE, GL_FALSE); bindDeferredShader(gDeferredSpotLightProgram); @@ -8755,7 +8866,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - fullscreen lights"); LLGLDepthTest depth(GL_FALSE); - + LL_PROFILE_GPU_ZONE("fullscreen lights"); // full screen blit gGL.pushMatrix(); gGL.loadIdentity(); @@ -8851,6 +8962,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) gGL.loadIdentity(); { + LL_PROFILE_GPU_ZONE("gamma correct"); LLGLDepthTest depth(GL_FALSE, GL_FALSE); LLVector2 tc1(0, 0); @@ -8930,6 +9042,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) popRenderTypeMask(); } + if (!gCubeSnapshot) { // render highlights, etc. renderHighlights(); @@ -9041,6 +9154,7 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f); } + //if (!gCubeSnapshot) { LLDrawable* potential = drawablep; //determine if this is a good light for casting shadows @@ -9092,14 +9206,15 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) { - LLRenderTarget* deferred_target = &mDeferredScreen; - LLRenderTarget* deferred_depth_target = &mDeferredDepth; - LLRenderTarget* deferred_light_target = &mDeferredLight; + LLRenderTarget* deferred_target = &mRT->deferredScreen; + LLRenderTarget* deferred_depth_target = &mRT->deferredDepth; + LLRenderTarget* deferred_light_target = &mRT->deferredLight; stop_glerror(); shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, deferred_target->getUsage()); shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, deferred_target->getUsage()); shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, deferred_target->getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_EMISSIVE, deferred_target->getUsage()); shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_depth_target->getUsage()); shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, deferred_light_target->getUsage()); shader.disableTexture(LLShaderMgr::DIFFUSE_MAP); @@ -9133,11 +9248,59 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) cube_map->disable(); } } + + unbindReflectionProbes(shader); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(0)->activate(); shader.unbind(); } +void LLPipeline::bindReflectionProbes(LLGLSLShader& shader) +{ + S32 channel = shader.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); + bool bound = false; + if (channel > -1 && mReflectionMapManager.mTexture.notNull()) + { + mReflectionMapManager.mTexture->bind(channel); + bound = true; + } + + channel = shader.enableTexture(LLShaderMgr::IRRADIANCE_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY); + if (channel > -1 && mReflectionMapManager.mIrradianceMaps.notNull()) + { + mReflectionMapManager.mIrradianceMaps->bind(channel); + bound = true; + } + + if (bound) + { + mReflectionMapManager.setUniforms(); + + F32* m = gGLModelView; + + F32 mat[] = { m[0], m[1], m[2], + m[4], m[5], m[6], + m[8], m[9], m[10] }; + + shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat); + } +} + +void LLPipeline::unbindReflectionProbes(LLGLSLShader& shader) +{ + S32 channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP); + if (channel > -1 && mReflectionMapManager.mTexture.notNull()) + { + mReflectionMapManager.mTexture->unbind(); + if (channel == 0) + { + gGL.getTexUnit(channel)->enable(LLTexUnit::TT_TEXTURE); + } + } +} + + inline float sgn(float a) { if (a > 0.0F) return (1.0F); @@ -9148,8 +9311,9 @@ inline float sgn(float a) void LLPipeline::generateWaterReflection(LLCamera& camera_in) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + LL_PROFILE_GPU_ZONE("generateWaterReflection"); - if (!assertInitialized()) + if (!assertInitialized() || gCubeSnapshot) { return; } @@ -9559,7 +9723,7 @@ static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbri void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER); - + LL_PROFILE_GPU_ZONE("renderShadow"); //disable occlusion culling for shadow passes (save setting to restore later) S32 occlude = LLPipeline::sUseOcclusion; if (!use_occlusion) @@ -9582,6 +9746,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LLRenderPass::PASS_NORMMAP_EMISSIVE, LLRenderPass::PASS_NORMSPEC, LLRenderPass::PASS_NORMSPEC_EMISSIVE, + LLRenderPass::PASS_PBR_OPAQUE, // NOTE: Assumes PASS_PBR_OPAQUE_RIGGED is consecutive + //LLRenderPass::PASS_PBR_OPAQUE_RIGGED, }; LLGLEnable cull(GL_CULL_FACE); @@ -9594,7 +9760,9 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gDeferredShadowCubeProgram.bind(); } - LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID - 1]; + LLRenderTarget& occlusion_target = LLViewerCamera::sCurCameraID >= LLViewerCamera::CAMERA_SPOT_SHADOW0 ? + mSpotShadowOcclusion[LLViewerCamera::sCurCameraID - LLViewerCamera::CAMERA_SPOT_SHADOW0] : + mRT->shadowOcclusion[LLViewerCamera::sCurCameraID - LLViewerCamera::CAMERA_SUN_SHADOW0]; occlusion_target.bindTarget(); updateCull(shadow_cam, result); @@ -9646,7 +9814,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera } LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow simple"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE); - + LL_PROFILE_GPU_ZONE("shadow simple"); gGL.getTexUnit(0)->disable(); for (U32 i = 0; i < sizeof(types) / sizeof(U32); ++i) { @@ -9679,7 +9847,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA); - + LL_PROFILE_GPU_ZONE("shadow alpha"); for (int i = 0; i < 2; ++i) { bool rigged = i == 1; @@ -9738,9 +9906,14 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); - LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID - 1]; + LLRenderTarget& occlusion_source = LLViewerCamera::sCurCameraID >= LLViewerCamera::CAMERA_SPOT_SHADOW0 ? + mSpotShadow[LLViewerCamera::sCurCameraID - LLViewerCamera::CAMERA_SPOT_SHADOW0] : + mRT->shadow[LLViewerCamera::sCurCameraID - LLViewerCamera::CAMERA_SUN_SHADOW0]; - doOcclusion(shadow_cam, occlusion_source, occlusion_target); + if (occlude > 1) + { + doOcclusion(shadow_cam, occlusion_source, occlusion_target); + } if (use_shader) { @@ -9961,7 +10134,8 @@ void LLPipeline::generateHighlight(LLCamera& camera) { mHighlightSet.insert(HighlightItem(mHighlightObject)); } - + llassert(!gCubeSnapshot); + if (!mHighlightSet.empty()) { F32 transition = gFrameIntervalSeconds.value()/RenderHighlightFadeTime; @@ -10009,9 +10183,16 @@ void LLPipeline::generateHighlight(LLCamera& camera) } } -LLRenderTarget* LLPipeline::getShadowTarget(U32 i) +LLRenderTarget* LLPipeline::getSunShadowTarget(U32 i) { - return &mShadow[i]; + llassert(i < 4); + return &mRT->shadow[i]; +} + +LLRenderTarget* LLPipeline::getSpotShadowTarget(U32 i) +{ + llassert(i < 2); + return &mSpotShadow[i]; } static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow"); @@ -10025,6 +10206,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) } LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW); + LL_PROFILE_GPU_ZONE("generateSunShadow"); bool skip_avatar_update = false; if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) @@ -10107,6 +10289,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND_RIGGED, LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK_RIGGED, LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE_RIGGED, + LLPipeline::RENDER_TYPE_PASS_PBR_OPAQUE, + LLPipeline::RENDER_TYPE_PASS_PBR_OPAQUE_RIGGED, END_RENDER_TYPES); gGL.setColorMask(false, false); @@ -10136,6 +10320,12 @@ void LLPipeline::generateSunShadow(LLCamera& camera) clip = RenderShadowOrthoClipPlanes; mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]); + //if (gCubeSnapshot) + { //always do a single 64m shadow in reflection maps + mSunClipPlanes.set(64.f, 128.f, 256.f); + mSunOrthoClipPlanes.set(64.f, 128.f, 256.f); + } + //currently used for amount to extrude frusta corners for constructing shadow frusta //LLVector3 n = RenderShadowNearDist; //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; @@ -10252,28 +10442,41 @@ void LLPipeline::generateSunShadow(LLCamera& camera) // convenience array of 4 near clip plane distances F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] }; - if (mSunDiffuse == LLColor4::black) - { //sun diffuse is totally black, shadows don't matter + { //sun diffuse is totally shadows don't matter LLGLDepthTest depth(GL_TRUE); for (S32 j = 0; j < 4; j++) { - mShadow[j].bindTarget(); - mShadow[j].clear(); - mShadow[j].flush(); + mRT->shadow[j].bindTarget(); + mRT->shadow[j].clear(); + mRT->shadow[j].flush(); } } else { - for (S32 j = 0; j < 4; j++) + /*if (gCubeSnapshot) + { + // do one shadow split for cube snapshots, clear the rest + mSunClipPlanes.set(64.f, 64.f, 64.f); + dist[1] = dist[2] = dist[3] = dist[4] = 64.f; + for (S32 j = 1; j < 4; j++) + { + mRT->shadow[j].bindTarget(); + mRT->shadow[j].clear(); + mRT->shadow[j].flush(); + } + }*/ + + //for (S32 j = 0; j < (gCubeSnapshot ? 1 : 4); j++) + for (S32 j = 0; j < 4; j++) { if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA)) { mShadowFrustPoints[j].clear(); } - LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW0+j); + LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SUN_SHADOW0+j); //restore render matrices set_current_modelview(saved_view); @@ -10327,12 +10530,12 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mShadowCamera[j+4] = shadow_cam; } - mShadow[j].bindTarget(); + mRT->shadow[j].bindTarget(); { LLGLDepthTest depth(GL_TRUE); - mShadow[j].clear(); + mRT->shadow[j].clear(); } - mShadow[j].flush(); + mRT->shadow[j].flush(); mShadowError.mV[j] = 0.f; mShadowFOV.mV[j] = 0.f; @@ -10619,18 +10822,18 @@ void LLPipeline::generateSunShadow(LLCamera& camera) stop_glerror(); - mShadow[j].bindTarget(); - mShadow[j].getViewport(gGLViewport); - mShadow[j].clear(); + mRT->shadow[j].bindTarget(); + mRT->shadow[j].getViewport(gGLViewport); + mRT->shadow[j].clear(); - U32 target_width = mShadow[j].getWidth(); + U32 target_width = mRT->shadow[j].getWidth(); { static LLCullResult result[4]; renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE, FALSE, target_width); } - mShadow[j].flush(); + mRT->shadow[j].flush(); if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) { @@ -10645,142 +10848,150 @@ void LLPipeline::generateSunShadow(LLCamera& camera) if (gen_shadow) { - LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat(); - F32 fade_amt = gFrameIntervalSeconds.value() - * llmax(LLTrace::get_frame_recording().getLastRecording().getSum(*velocity_stat) / LLTrace::get_frame_recording().getLastRecording().getDuration().value(), 1.0); + if (!gCubeSnapshot) //skip updating spot shadow maps during cubemap updates + { + LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat(); + F32 fade_amt = gFrameIntervalSeconds.value() + * llmax(LLTrace::get_frame_recording().getLastRecording().getSum(*velocity_stat) / LLTrace::get_frame_recording().getLastRecording().getDuration().value(), 1.0); - //update shadow targets - for (U32 i = 0; i < 2; i++) - { //for each current shadow - LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW4+i); + //update shadow targets + for (U32 i = 0; i < 2; i++) + { //for each current shadow + LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SPOT_SHADOW0 + i); + + if (mShadowSpotLight[i].notNull() && + (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || + mShadowSpotLight[i] == mTargetShadowSpotLight[1])) + { //keep this spotlight + mSpotLightFade[i] = llmin(mSpotLightFade[i] + fade_amt, 1.f); + } + else + { //fade out this light + mSpotLightFade[i] = llmax(mSpotLightFade[i] - fade_amt, 0.f); - if (mShadowSpotLight[i].notNull() && - (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || - mShadowSpotLight[i] == mTargetShadowSpotLight[1])) - { //keep this spotlight - mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f); - } - else - { //fade out this light - mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f); - - if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) - { //faded out, grab one of the pending spots (whichever one isn't already taken) - if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2]) - { - mShadowSpotLight[i] = mTargetShadowSpotLight[0]; - } - else - { - mShadowSpotLight[i] = mTargetShadowSpotLight[1]; - } - } - } - } + if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull()) + { //faded out, grab one of the pending spots (whichever one isn't already taken) + if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i + 1) % 2]) + { + mShadowSpotLight[i] = mTargetShadowSpotLight[0]; + } + else + { + mShadowSpotLight[i] = mTargetShadowSpotLight[1]; + } + } + } + } + } - for (S32 i = 0; i < 2; i++) - { - set_current_modelview(saved_view); - set_current_projection(saved_proj); + for (S32 i = 0; i < 2; i++) + { + set_current_modelview(saved_view); + set_current_projection(saved_proj); - if (mShadowSpotLight[i].isNull()) - { - continue; - } + if (mShadowSpotLight[i].isNull()) + { + continue; + } - LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); + LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume(); - if (!volume) - { - mShadowSpotLight[i] = NULL; - continue; - } + if (!volume) + { + mShadowSpotLight[i] = NULL; + continue; + } - LLDrawable* drawable = mShadowSpotLight[i]; + LLDrawable* drawable = mShadowSpotLight[i]; - LLVector3 params = volume->getSpotLightParams(); - F32 fov = params.mV[0]; + LLVector3 params = volume->getSpotLightParams(); + F32 fov = params.mV[0]; - //get agent->light space matrix (modelview) - LLVector3 center = drawable->getPositionAgent(); - LLQuaternion quat = volume->getRenderRotation(); + //get agent->light space matrix (modelview) + LLVector3 center = drawable->getPositionAgent(); + LLQuaternion quat = volume->getRenderRotation(); - //get near clip plane - LLVector3 scale = volume->getScale(); - LLVector3 at_axis(0,0,-scale.mV[2]*0.5f); - at_axis *= quat; + //get near clip plane + LLVector3 scale = volume->getScale(); + LLVector3 at_axis(0, 0, -scale.mV[2] * 0.5f); + at_axis *= quat; - LLVector3 np = center+at_axis; - at_axis.normVec(); + LLVector3 np = center + at_axis; + at_axis.normVec(); - //get origin that has given fov for plane np, at_axis, and given scale - F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f); + //get origin that has given fov for plane np, at_axis, and given scale + F32 dist = (scale.mV[1] * 0.5f) / tanf(fov * 0.5f); - LLVector3 origin = np - at_axis*dist; + LLVector3 origin = np - at_axis * dist; - LLMatrix4 mat(quat, LLVector4(origin, 1.f)); + LLMatrix4 mat(quat, LLVector4(origin, 1.f)); - view[i+4] = glh::matrix4f((F32*) mat.mMatrix); + view[i + 4] = glh::matrix4f((F32*)mat.mMatrix); - view[i+4] = view[i+4].inverse(); + view[i + 4] = view[i + 4].inverse(); - //get perspective matrix - F32 near_clip = dist+0.01f; - F32 width = scale.mV[VX]; - F32 height = scale.mV[VY]; - F32 far_clip = dist+volume->getLightRadius()*1.5f; + //get perspective matrix + F32 near_clip = dist + 0.01f; + F32 width = scale.mV[VX]; + F32 height = scale.mV[VY]; + F32 far_clip = dist + volume->getLightRadius() * 1.5f; - F32 fovy = fov * RAD_TO_DEG; - F32 aspect = width/height; - - proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip); + F32 fovy = fov * RAD_TO_DEG; + F32 aspect = width / height; - //translate and scale to from [-1, 1] to [0, 1] - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); + proj[i + 4] = gl_perspective(fovy, aspect, near_clip, far_clip); - set_current_modelview(view[i+4]); - set_current_projection(proj[i+4]); + //translate and scale to from [-1, 1] to [0, 1] + glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, + 0.f, 0.5f, 0.f, 0.5f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f); - mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; - - for (U32 j = 0; j < 16; j++) - { - gGLLastModelView[j] = mShadowModelview[i+4].m[j]; - gGLLastProjection[j] = mShadowProjection[i+4].m[j]; - } + set_current_modelview(view[i + 4]); + set_current_projection(proj[i + 4]); - mShadowModelview[i+4] = view[i+4]; - mShadowProjection[i+4] = proj[i+4]; + mSunShadowMatrix[i + 4] = trans * proj[i + 4] * view[i + 4] * inv_view; - LLCamera shadow_cam = camera; - shadow_cam.setFar(far_clip); - shadow_cam.setOrigin(origin); + for (U32 j = 0; j < 16; j++) + { + gGLLastModelView[j] = mShadowModelview[i + 4].m[j]; + gGLLastProjection[j] = mShadowProjection[i + 4].m[j]; + } - LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + mShadowModelview[i + 4] = view[i + 4]; + mShadowProjection[i + 4] = proj[i + 4]; - stop_glerror(); + if (!gCubeSnapshot) //skip updating spot shadow maps during cubemap updates + { + LLCamera shadow_cam = camera; + shadow_cam.setFar(far_clip); + shadow_cam.setOrigin(origin); + + LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE); + + stop_glerror(); - mShadow[i+4].bindTarget(); - mShadow[i+4].getViewport(gGLViewport); - mShadow[i+4].clear(); + // + + mSpotShadow[i].bindTarget(); + mSpotShadow[i].getViewport(gGLViewport); + mSpotShadow[i].clear(); - U32 target_width = mShadow[i+4].getWidth(); + U32 target_width = mSpotShadow[i].getWidth(); - static LLCullResult result[2]; + static LLCullResult result[2]; - LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW0 + i + 4); + LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SPOT_SHADOW0 + i); - RenderSpotLight = drawable; + RenderSpotLight = drawable; - renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE, target_width); + renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], FALSE, FALSE, target_width); - RenderSpotLight = nullptr; + RenderSpotLight = nullptr; - mShadow[i+4].flush(); - } + mSpotShadow[i].flush(); + } + } } else { //no spotlight shadows @@ -10853,6 +11064,7 @@ static LLTrace::BlockTimerStatHandle FTM_GENERATE_IMPOSTOR("Generate Impostor"); void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) { LL_RECORD_BLOCK_TIME(FTM_GENERATE_IMPOSTOR); + LL_PROFILE_GPU_ZONE("generateImpostor"); LLGLState::checkStates(); LLGLState::checkTextureChannels(); @@ -10923,22 +11135,47 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) { markVisible(avatar->mDrawable, *viewer_camera); - LLVOAvatar::attachment_map_t::iterator iter; - for (iter = avatar->mAttachmentPoints.begin(); - iter != avatar->mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment *attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - if (LLViewerObject* attached_object = attachment_iter->get()) - { - markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); - } - } - } + if (preview_avatar) + { + // Only show rigged attachments for preview + LLVOAvatar::attachment_map_t::iterator iter; + for (iter = avatar->mAttachmentPoints.begin(); + iter != avatar->mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object && attached_object->isRiggedMesh()) + { + markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + } + } + } + } + else + { + LLVOAvatar::attachment_map_t::iterator iter; + for (iter = avatar->mAttachmentPoints.begin(); + iter != avatar->mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object) + { + markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + } + } + } + } } stateSort(*LLViewerCamera::getInstance(), result); @@ -11096,7 +11333,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) if (LLPipeline::sRenderDeferred) { GLuint buff = GL_COLOR_ATTACHMENT0; - LL_PROFILER_GPU_ZONEC( "gl.DrawBuffersARB", 0x8000FF ); glDrawBuffersARB(1, &buff); } @@ -11497,3 +11733,9 @@ void LLPipeline::restoreHiddenObject( const LLUUID& id ) } } +void LLPipeline::overrideEnvironmentMap() +{ + //mReflectionMapManager.mProbes.clear(); + //mReflectionMapManager.addProbe(LLViewerCamera::instance().getOrigin()); +} + diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 62d3ae7a39..cd7d0b88d8 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -38,6 +38,7 @@ #include "llgl.h" #include "lldrawable.h" #include "llrendertarget.h" +#include "llreflectionmapmanager.h" #include <stack> @@ -187,6 +188,7 @@ public: LLViewerObject* lineSegmentIntersectInWorld(const LLVector4a& start, const LLVector4a& end, bool pick_transparent, bool pick_rigged, + bool pick_unselectable, S32* face_hit, // return the face hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point @@ -216,8 +218,9 @@ public: U32 addObject(LLViewerObject *obj); void enableShadows(const bool enable_shadows); - void releaseShadowTargets(); - void releaseShadowTarget(U32 index); + void releaseSpotShadowTargets(); + void releaseSunShadowTargets(); + void releaseSunShadowTarget(U32 index); // void setLocalLighting(const bool local_lighting); // bool isLocalLightingEnabled() const; @@ -293,12 +296,17 @@ public: void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep); void unbindDeferredShader(LLGLSLShader& shader); + + void bindReflectionProbes(LLGLSLShader& shader); + void unbindReflectionProbes(LLGLSLShader& shader); + void renderDeferredLighting(LLRenderTarget* light_target); void postDeferredGammaCorrect(LLRenderTarget* screen_target); void generateWaterReflection(LLCamera& camera); void generateSunShadow(LLCamera& camera); - LLRenderTarget* getShadowTarget(U32 i); + LLRenderTarget* getSunShadowTarget(U32 i); + LLRenderTarget* getSpotShadowTarget(U32 i); void generateHighlight(LLCamera& camera); void renderHighlight(const LLViewerObject* obj, F32 fade); @@ -426,6 +434,9 @@ public: void hideObject( const LLUUID& id ); void restoreHiddenObject( const LLUUID& id ); + LLReflectionMapManager mReflectionMapManager; + void overrideEnvironmentMap(); + private: void unloadShaders(); void addToQuickLookup( LLDrawPool* new_poolp ); @@ -517,6 +528,8 @@ public: RENDER_TYPE_PASS_NORMSPEC_MASK_RIGGED = LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, RENDER_TYPE_PASS_NORMSPEC_EMISSIVE = LLRenderPass::PASS_NORMSPEC_EMISSIVE, RENDER_TYPE_PASS_NORMSPEC_EMISSIVE_RIGGED = LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, + RENDER_TYPE_PASS_PBR_OPAQUE = LLRenderPass::PASS_PBR_OPAQUE, + RENDER_TYPE_PASS_PBR_OPAQUE_RIGGED = LLRenderPass::PASS_PBR_OPAQUE_RIGGED, // Following are object types (only used in drawable mRenderType) RENDER_TYPE_HUD = LLRenderPass::NUM_RENDER_TYPES, RENDER_TYPE_VOLUME, @@ -574,7 +587,8 @@ public: RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used RENDER_DEBUG_TEXEL_DENSITY = 0x40000000, RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000, - RENDER_DEBUG_IMPOSTORS = 0x100000000 + RENDER_DEBUG_IMPOSTORS = 0x100000000, + RENDER_DEBUG_REFLECTION_PROBES = 0x200000000 }; public: @@ -626,26 +640,48 @@ public: static bool sRenderAttachedLights; static bool sRenderAttachedParticles; static bool sRenderDeferred; + static bool sRenderPBR; static S32 sVisibleLightCount; static bool sRenderingHUDs; static F32 sDistortionWaterClipPlaneMargin; static LLTrace::EventStatHandle<S64> sStatBatchSize; - //screen texture - U32 mScreenWidth; - U32 mScreenHeight; - - LLRenderTarget mScreen; - LLRenderTarget mUIScreen; - LLRenderTarget mDeferredScreen; - LLRenderTarget mFXAABuffer; - LLRenderTarget mEdgeMap; - LLRenderTarget mDeferredDepth; - LLRenderTarget mOcclusionDepth; - LLRenderTarget mDeferredLight; - LLRenderTarget mHighlight; - LLRenderTarget mPhysicsDisplay; + class RenderTargetPack + { + public: + U32 width = 0; + U32 height = 0; + + //screen texture + LLRenderTarget screen; + LLRenderTarget uiScreen; + LLRenderTarget deferredScreen; + LLRenderTarget fxaaBuffer; + LLRenderTarget edgeMap; + LLRenderTarget deferredDepth; + LLRenderTarget occlusionDepth; + LLRenderTarget deferredLight; + + //sun shadow map + LLRenderTarget shadow[4]; + LLRenderTarget shadowOcclusion[4]; + }; + + // main full resoltuion render target + RenderTargetPack mMainRT; + + // auxillary 512x512 render target pack + RenderTargetPack mAuxillaryRT; + + // currently used render target pack + RenderTargetPack* mRT; + + LLRenderTarget mSpotShadow[2]; + LLRenderTarget mSpotShadowOcclusion[2]; + + LLRenderTarget mHighlight; + LLRenderTarget mPhysicsDisplay; LLCullResult mSky; LLCullResult mReflectedObjects; @@ -657,15 +693,16 @@ public: //utility buffer for rendering cubes, 8 vertices are corners of a cube [-1, 1] LLPointer<LLVertexBuffer> mCubeVB; - //sun shadow map - LLRenderTarget mShadow[6]; - LLRenderTarget mShadowOcclusion[6]; + //list of currently bound reflection maps + std::vector<LLReflectionMap*> mReflectionMaps; + std::vector<LLVector3> mShadowFrustPoints[4]; LLVector4 mShadowError; LLVector4 mShadowFOV; LLVector3 mShadowFrustOrigin[4]; LLCamera mShadowCamera[8]; LLVector3 mShadowExtents[4][2]; + // TODO : separate Sun Shadow and Spot Shadow matrices glh::matrix4f mSunShadowMatrix[6]; glh::matrix4f mShadowModelview[6]; glh::matrix4f mShadowProjection[6]; @@ -860,6 +897,7 @@ protected: LLDrawPool* mBumpPool; LLDrawPool* mMaterialsPool; LLDrawPool* mWLSkyPool; + LLDrawPool* mPBROpaquePool; // Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar public: diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png Binary files differnew file mode 100644 index 0000000000..9a81c5f94b --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png Binary files differnew file mode 100644 index 0000000000..88012cf8d1 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png Binary files differnew file mode 100644 index 0000000000..ab02e7d42d --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png Binary files differnew file mode 100644 index 0000000000..63b4bd2127 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png Binary files differnew file mode 100644 index 0000000000..4200182b0c --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png Binary files differnew file mode 100644 index 0000000000..e12887f489 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png diff --git a/indra/newview/skins/default/textures/icons/Inv_Material.png b/indra/newview/skins/default/textures/icons/Inv_Material.png Binary files differnew file mode 100644 index 0000000000..f5918ceaed --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Inv_Material.png diff --git a/indra/newview/skins/default/textures/map_ui_collapse_icon.png b/indra/newview/skins/default/textures/map_ui_collapse_icon.png Binary files differnew file mode 100644 index 0000000000..e4de49d4af --- /dev/null +++ b/indra/newview/skins/default/textures/map_ui_collapse_icon.png diff --git a/indra/newview/skins/default/textures/map_ui_expand_icon.png b/indra/newview/skins/default/textures/map_ui_expand_icon.png Binary files differnew file mode 100644 index 0000000000..08734b4cc0 --- /dev/null +++ b/indra/newview/skins/default/textures/map_ui_expand_icon.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index a36b859b6c..f18dff5b22 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -303,6 +303,7 @@ with the same filename but different name <texture name="Inv_LostClosed" file_name="icons/Inv_LostClosed.png" preload="false" /> <texture name="Inv_LostOpen" file_name="icons/Inv_LostOpen.png" preload="false" /> <texture name="Inv_Landmark" file_name="icons/Inv_Landmark.png" preload="false" /> + <texture name="Inv_Material" file_name="icons/Inv_Material.png" preload="false" /> <texture name="Inv_Mesh" file_name="icons/Inv_Mesh.png" preload="false" /> <texture name="Inv_Notecard" file_name="icons/Inv_Notecard.png" preload="false" /> <texture name="Inv_Object" file_name="icons/Inv_Object.png" preload="false" /> @@ -447,6 +448,13 @@ with the same filename but different name <texture name="OptionsMenu_Off" file_name="icons/OptionsMenu_Off.png" preload="false" /> <texture name="OptionsMenu_Press" file_name="icons/OptionsMenu_Press.png" preload="false" /> + <texture name="ClipboardSmallMenu_Disabled" file_name="icons/ClipboardSmallMenu_Disabled.png" preload="false" /> + <texture name="ClipboardSmallMenu_Off" file_name="icons/ClipboardSmallMenu_Off.png" preload="false" /> + <texture name="ClipboardSmallMenu_Press" file_name="icons/ClipboardSmallMenu_Press.png" preload="false" /> + <texture name="ClipboardMenu_Disabled" file_name="icons/ClipboardMenu_Disabled.png" preload="false" /> + <texture name="ClipboardMenu_Off" file_name="icons/ClipboardMenu_Off.png" preload="false" /> + <texture name="ClipboardMenu_Press" file_name="icons/ClipboardMenu_Press.png" preload="false" /> + <texture name="OutboxStatus_Success" file_name="green_checkmark.png" preload="false" /> <texture name="OutboxStatus_Warning" file_name="icons/pop_up_caution.png" preload="false" /> <texture name="OutboxStatus_Error" file_name="red_x.png" preload="false" /> @@ -612,8 +620,7 @@ with the same filename but different name <texture name="login_sl_logo" file_name="windows/login_sl_logo.png" preload="true" /> <texture name="login_sl_logo_small" file_name="windows/login_sl_logo_small.png" preload="true" /> - <texture name="first_login_image_left" file_name="windows/first_login_image_left.png" preload="true" /> - <texture name="first_login_image_right" file_name="windows/first_login_image_right.png" preload="true" /> + <texture name="first_login_image" file_name="windows/first_login_image.jpg" preload="true" /> <texture name="Stepper_Down_Off" file_name="widgets/Stepper_Down_Off.png" preload="false" /> <texture name="Stepper_Down_Press" file_name="widgets/Stepper_Down_Press.png" preload="false" /> @@ -804,6 +811,8 @@ with the same filename but different name <texture name="map_infohub.tga" /> <texture name="map_telehub.tga" /> <texture name="map_track_16.tga" /> + <texture name="map_ui_collapse_icon.png" /> + <texture name="map_ui_expand_icon.png" /> <texture name="notify_caution_icon.tga" /> diff --git a/indra/newview/skins/default/textures/windows/first_login_image.jpg b/indra/newview/skins/default/textures/windows/first_login_image.jpg Binary files differnew file mode 100644 index 0000000000..30f31341ed --- /dev/null +++ b/indra/newview/skins/default/textures/windows/first_login_image.jpg diff --git a/indra/newview/skins/default/textures/windows/first_login_image_left.png b/indra/newview/skins/default/textures/windows/first_login_image_left.png Binary files differdeleted file mode 100644 index 77904d7d12..0000000000 --- a/indra/newview/skins/default/textures/windows/first_login_image_left.png +++ /dev/null diff --git a/indra/newview/skins/default/textures/windows/first_login_image_right.png b/indra/newview/skins/default/textures/windows/first_login_image_right.png Binary files differdeleted file mode 100644 index 35ecce9c07..0000000000 --- a/indra/newview/skins/default/textures/windows/first_login_image_right.png +++ /dev/null diff --git a/indra/newview/skins/default/xui/da/strings.xml b/indra/newview/skins/default/xui/da/strings.xml index 814305c1bc..5f1bf73f26 100644 --- a/indra/newview/skins/default/xui/da/strings.xml +++ b/indra/newview/skins/default/xui/da/strings.xml @@ -106,7 +106,7 @@ <string name="LoginFailedNoNetwork"> Netværksfejl: Kunne ikke etablere forbindelse, check venligst din netværksforbindelse. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Login fejlede. </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index ba26f721fe..97ace4fc18 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -186,7 +186,7 @@ Voice-Server-Version: [VOICE_VERSION] <string name="LoginFailedNoNetwork"> Netzwerkfehler: Verbindung konnte nicht hergestellt werden. Bitte überprüfen Sie Ihre Netzwerkverbindung. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Anmeldung fehlgeschlagen </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index b2d9e53039..dee5e29a3c 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -164,6 +164,7 @@ left_pad="2" name="Description" spellcheck="true" + parse_urls="true" top_delta="0" width="365" word_wrap="true" /> diff --git a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml index d783d1e23c..e91efb89b2 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml @@ -2,7 +2,7 @@ <floater legacy_header_height="18" can_minimize="false" - height="466" + height="486" layout="topleft" name="Inventory Finder" help_topic="inventory_finder" @@ -95,12 +95,29 @@ width="126" /> <icon height="16" + image_name="Inv_Material" + layout="topleft" + left="8" + mouse_opaque="true" + name="icon_material" + top="122" + width="16" /> + <check_box + height="16" + label="Materials" + layout="topleft" + left_pad="2" + name="check_material" + top_delta="0" + width="126" /> + <icon + height="16" image_name="Inv_Notecard" layout="topleft" left="8" mouse_opaque="true" name="icon_notecard" - top="122" + top="142" width="16" /> <check_box height="16" @@ -117,7 +134,7 @@ left="8" mouse_opaque="true" name="icon_object" - top="142" + top="162" width="16" /> <check_box height="16" @@ -134,7 +151,7 @@ left="8" mouse_opaque="true" name="icon_script" - top="162" + top="182" width="16" /> <check_box height="16" @@ -151,7 +168,7 @@ left="8" mouse_opaque="true" name="icon_sound" - top="182" + top="202" width="16" /> <check_box height="16" @@ -168,7 +185,7 @@ left="8" mouse_opaque="true" name="icon_texture" - top="202" + top="222" width="16" /> <check_box height="16" @@ -185,7 +202,7 @@ left="8" mouse_opaque="true" name="icon_snapshot" - top="222" + top="242" width="16" /> <check_box height="16" @@ -202,7 +219,7 @@ left="8" mouse_opaque="true" name="icon_settings" - top="242" + top="262" width="16" /> <check_box height="16" @@ -220,7 +237,7 @@ layout="topleft" left="8" name="All" - top="262" + top="282" width="100" /> <button height="20" @@ -274,7 +291,7 @@ width="260"/> <check_box height="16" - top="352" + top="372" label="Since Logoff" layout="topleft" left_delta="0" @@ -290,7 +307,7 @@ layout="topleft" left_delta="0" name="- OR -" - top="370" + top="390" width="144"> - OR - </text> @@ -298,7 +315,7 @@ height="16" layout="topleft" name="date_search_direction" - top="388" + top="408" left="8" width="270"> <radio_item @@ -368,6 +385,6 @@ layout="topleft" name="Close" right="-6" - top="434" + top="454" width="76" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_material_editor.xml b/indra/newview/skins/default/xui/en/floater_material_editor.xml new file mode 100644 index 0000000000..0a05a4f868 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_material_editor.xml @@ -0,0 +1,504 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + can_resize="false" + default_tab_group="1" + height="887" + layout="topleft" + name="material editor" + help_topic="material_editor" + title="[MATERIAL_NAME]" + width="256"> + <string name="no_upload_fee_string">no upload fee</string> + <string name="upload_fee_string">L$[FEE] upload fee</string> + <check_box + follows="left|top" + label="Double Sided" + left="14" + top="14" + name="double sided" + height="25" + width="120" /> + <panel + border="true" + follows="left|top" + width="246" + height="196" + layout="topleft" + left="5" + mouse_opaque="false" + name="albedo_texture_pnl" + top_pad="5" + > + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + layout="topleft" + left="10" + top="5" + width="64"> + Albedo: + </text> + <texture_picker + can_apply_immediately="true" + default_image_name="Default" + fallback_image="materials_ui_x_24.png" + allow_no_texture="true" + follows="left|top" + top_pad="8" + height="151" + layout="topleft" + left="10" + name="albedo_texture" + tool_tip="Albedo map. Alpha channel is optional and used for transparency." + width="128" /> + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + width="128" + layout="topleft" + left="10" + top_pad="-17" + name="albedo_upload_fee" + > + No upload fee + </text> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left_pad="5" + top="8" + > + Tint + </text> + <color_swatch + can_apply_immediately="true" + follows="left|top" + height="40" + label_height="0" + layout="topleft" + left_delta="0" + top_pad="5" + name="albedo color" + width="40" /> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="5" + width="96" + > + Transparency + </text> + <spinner + decimal_digits="3" + follows="left|top" + height="19" + increment="0.01" + initial_value="1" + layout="topleft" + left_delta="0" + top_pad="5" + min_val="0" + max_val="1" + name="transparency" + width="64" + /> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left_delta="0" + name="label alphamode" + text_readonly_color="LabelDisabledColor" + top_pad="5" + width="90"> + Alpha mode + </text> + <combo_box + height="23" + layout="topleft" + left_delta="0" + name="alpha mode" + top_pad="4" + width="96"> + <combo_box.item + label="None" + name="None" + value="OPAQUE" /> + <combo_box.item + label="Alpha blending" + name="Alpha blending" + value="BLEND" /> + <combo_box.item + label="Alpha masking" + name="Alpha masking" + value="MASK" /> + </combo_box> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="5" + width="96" + > + Alpha Cutoff + </text> + <spinner + decimal_digits="3" + follows="left|top" + height="19" + increment="0.01" + initial_value="1" + layout="topleft" + left_delta="0" + top_pad="5" + min_val="0" + max_val="1" + name="alpha cutoff" + width="64" + /> + </panel> + <panel + border="true" + follows="left|top" + width="246" + height="175" + layout="topleft" + left="5" + mouse_opaque="false" + name="metallic_texture_pnl" + top_pad="5" + > + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + layout="topleft" + left="10" + top="5" + > + Metallic-Roughness: + </text> + <texture_picker + can_apply_immediately="true" + default_image_name="Default" + fallback_image="materials_ui_x_24.png" + allow_no_texture="true" + follows="left|top" + width="128" + height="151" + layout="topleft" + left="10" + name="metallic_roughness_texture" + tool_tip="GLTF metallic-roughness map with optional occlusion. Red channel is occlusion, green channel is roughness, blue channel is metalness." + top_pad="8" + /> + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + width="128" + layout="topleft" + left="10" + top_pad="-17" + name="metallic_upload_fee" + > + No upload fee + </text> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left_pad="5" + top="8" + > + Metallic Factor + </text> + <spinner + decimal_digits="3" + follows="left|top" + height="19" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="0" + top_pad="5" + min_val="0" + max_val="1" + name="metalness factor" + width="64" + /> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left_delta="0" + top_pad="5" + width="96" + > + Roughness Factor + </text> + <spinner + decimal_digits="3" + follows="left|top" + height="19" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="0" + top_pad="5" + min_val="0" + max_val="1" + name="roughness factor" + width="64" + /> + </panel> + <panel + border="true" + follows="left|top" + width="246" + height="175" + layout="topleft" + left="5" + mouse_opaque="false" + name="emissive_texture_pnl" + top_pad="5" + > + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + layout="topleft" + left="10" + top="5" + width="64"> + Emissive: + </text> + <texture_picker + can_apply_immediately="true" + default_image_name="Default" + fallback_image="materials_ui_x_24.png" + allow_no_texture="true" + follows="left|top" + top_pad="8" + height="151" + layout="topleft" + left="10" + name="emissive_texture" + width="128" /> + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + width="128" + layout="topleft" + left="10" + top_pad="-17" + name="emissive_upload_fee" + > + No upload fee + </text> + <text + type="string" + length="1" + follows="left|top" + height="10" + layout="topleft" + left_pad="5" + top="8" + > + Tint + </text> + <color_swatch + can_apply_immediately="true" + follows="left|top" + height="40" + label_height="0" + layout="topleft" + left_delta="0" + top_pad="5" + name="emissive color" + width="40" /> + <!--<text + type="string" + length="1" + follows="left|top" + height="10" + width="64" + layout="topleft" + left_delta="0" + top_pad="5" + > + Intensity + </text> + <spinner + decimal_digits="3" + follows="left|top" + height="19" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="0" + top_pad="5" + max_val="100" + width="64" + />--> + </panel> + <panel + border="true" + follows="left|top" + width="246" + height="175" + layout="topleft" + left="5" + mouse_opaque="false" + top_pad="5" + name="normal_texture_pnl" + > + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + layout="topleft" + left="10" + top="5" + width="64"> + Normal: + </text> + <texture_picker + can_apply_immediately="true" + default_image_name="Default" + fallback_image="materials_ui_x_24.png" + allow_no_texture="true" + follows="left|top" + top_pad="8" + height="151" + layout="topleft" + left="10" + name="normal_texture" + width="128" /> + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + width="128" + layout="topleft" + left="10" + top_pad="-17" + name="normal_upload_fee" + > + No upload fee + </text> + </panel> + + <panel + follows="right|bottom" + width="246" + height="97" + layout="bottomright" + top_delta="-2" + left="5" + name="button_panel" + > + <text + type="string" + name="unsaved_changes" + font.style="BOLD" + text_color="DrYellow" + length="1" + follows="left|top" + height="10" + width="200" + layout="topleft" + left="10" + top="0" + > + Usaved changes + </text> + <button + follows="left|top" + height="25" + label="Save" + layout="topleft" + name="save" + top_pad="7" + left="0" + width="120" /> + <button + follows="left|top" + height="25" + label="Save As..." + layout="topleft" + name="save_as" + top_delta="0" + left_pad="6" + width="120" /> + <text + type="string" + font.style="BOLD" + length="1" + follows="left|top" + height="10" + width="220" + layout="topleft" + left="10" + top_pad="5" + name="total_upload_fee" + > + Total upload fee: L$ [FEE] + </text> + + <view_border + bevel_style="none" + height="0" + layout="topleft" + left="0" + name="button_border" + top_pad="7" + width="246"/> + + <button + follows="left|top" + height="25" + label="Cancel" + layout="topleft" + name="cancel" + top_pad="7" + left="61" + width="121" /> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_my_environments.xml b/indra/newview/skins/default/xui/en/floater_my_environments.xml index 6aff387dcb..db81c8bba2 100644 --- a/indra/newview/skins/default/xui/en/floater_my_environments.xml +++ b/indra/newview/skins/default/xui/en/floater_my_environments.xml @@ -119,7 +119,7 @@ follows="all" layout="topleft" name="pnl_settings" - filter_asset_type="settings"/> + filter_asset_types="settings"/> </panel> </layout_panel> <layout_panel diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 0a4acd979a..97a87d56f4 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -272,51 +272,6 @@ Hardware </text> - <slider - control_name="RenderFogRatio" - follows="left|top" - height="16" - initial_value="4" - decimal_digits="1" - label="Fog Distance Ratio:" - label_width="185" - layout="topleft" - left="30" - name="fog" - min_val="0.5" - max_val="10" - increment="0.1" - top_delta="16" - width="332" /> - - <slider - control_name="RenderGamma" - follows="left|top" - height="16" - initial_value="1" - decimal_digits="2" - label="Gamma:" - label_width="185" - layout="topleft" - left="30" - name="gamma" - min_val="0" - max_val="2" - increment="0.01" - top_delta="16" - width="332" /> - <text - type="string" - length="1" - follows="left|top" - height="16" - layout="topleft" - left="30" - name="(brightness, lower is brighter)" - top_delta="16" - width="260"> - (0 = default brightness, lower = brighter) - </text> <check_box control_name="RenderAnisotropic" @@ -585,20 +540,6 @@ </check_box> <check_box - control_name="RenderObjectBump" - height="16" - initial_value="true" - label="Bump mapping and shiny" - layout="topleft" - left="420" - name="BumpShiny" - top_delta="16" - width="300"> - <check_box.commit_callback - function="Pref.RenderOptionUpdate" /> - </check_box> - - <check_box control_name="RenderLocalLights" height="16" initial_value="true" @@ -609,51 +550,6 @@ top_delta="16" width="300" /> - <slider - control_name="RenderTerrainDetail" - follows="left|top" - height="16" - label="Terrain Detail:" - label_width="165" - layout="topleft" - left="440" - show_text="false" - initial_value="0" - increment="1" - min_val="0" - max_val="1" - name="TerrainDetail" - top_delta="16" - width="280" > - <slider.commit_callback - function="Pref.UpdateSliderText" - parameter="TerrainDetail" /> - </slider> - <text - type="string" - length="1" - follows="left|top" - height="16" - layout="topleft" - top_delta="0" - left_delta="284" - name="TerrainDetailText" - text_readonly_color="LabelDisabledColor" - width="65"> - Low - </text> - - <check_box - control_name="RenderAvatarCloth" - height="16" - initial_value="true" - label="Avatar cloth" - layout="topleft" - left="440" - name="AvatarCloth" - top_delta="16" - width="280" /> - <text type="string" length="1" @@ -663,7 +559,7 @@ name="ReflectionsText" text_readonly_color="LabelDisabledColor" top_delta="16" - left="440" + left="420" width="128"> Water Reflections: </text> @@ -705,20 +601,6 @@ value="4"/> </combo_box> - <check_box - control_name="WindLightUseAtmosShaders" - height="16" - initial_value="true" - label="Atmospheric shaders" - layout="topleft" - left="440" - name="WindLightUseAtmosShaders" - top_delta="16" - width="280"> - <check_box.commit_callback - function="Pref.RenderOptionUpdate" /> - </check_box> - <slider control_name="WLSkyDetail" decimal_digits="0" @@ -729,7 +611,7 @@ label="Sky:" label_width="145" layout="topleft" - left="460" + left="420" min_val="16" max_val="128" name="SkyMeshDetail" @@ -755,26 +637,12 @@ </text> <check_box - control_name="RenderDeferred" - height="16" - initial_value="true" - label="Advanced Lighting Model" - layout="topleft" - left="460" - name="UseLightShaders" - top_delta="16" - width="260"> - <check_box.commit_callback - function="Pref.RenderOptionUpdate" /> - </check_box> - - <check_box control_name="RenderDeferredSSAO" height="16" initial_value="true" label="Ambient Occlusion" layout="topleft" - left="480" + left="420" name="UseSSAO" top_delta="16" width="240"> @@ -788,7 +656,7 @@ initial_value="true" label="Depth of Field" layout="topleft" - left="480" + left="420" name="UseDoF" top_delta="16" width="240"> @@ -796,29 +664,13 @@ function="Pref.RenderOptionUpdate" /> </check_box> - <!-- - <check_box - control_name="RenderUseAdvancedAtmospherics" - height="16" - initial_value="true" - label="Advanced Atmospherics" - layout="topleft" - left="480" - name="UseAdvancedAtmo" - top_delta="16" - width="240"> - <check_box.commit_callback - function="Pref.AdvancedAtmosphericsEnable" /> - </check_box> - --> - <text type="string" length="1" follows="left|top" height="16" layout="topleft" - left="480" + left="420" name="RenderShadowDetailText" text_readonly_color="LabelDisabledColor" top_delta="16" @@ -846,15 +698,49 @@ name="2" value="2"/> </combo_box> - -<!-- End of Advanced Settings block --> + <text + type="string" + length="1" + follows="left|top" + height="16" + layout="topleft" + left="420" + name="RenderReflectionDetailText" + text_readonly_color="LabelDisabledColor" + top_delta="16" + width="128"> + Reflections: + </text> + <combo_box + control_name="RenderReflectionProbeDetail" + height="18" + layout="topleft" + left_delta="130" + top_delta="0" + name="ReflectionDetial" + width="150"> + <combo_box.item + label="Static Only" + name="0" + value="0"/> + <combo_box.item + label="Static+Dynamic" + name="1" + value="1"/> + <combo_box.item + label="Realtime" + name="2" + value="2"/> + </combo_box> + + <!-- End of Advanced Settings block --> <view_border bevel_style="in" height="0" layout="topleft" left="13" name="horiz_border" - top_pad="21" + top="338" top_delta="5" width="774"/> <button @@ -864,7 +750,7 @@ layout="topleft" left="20" name="Defaults" - top_delta="10" + top_delta="20" width="210"> <button.commit_callback function="Pref.HardwareDefaults" /> diff --git a/indra/newview/skins/default/xui/en/floater_settings_picker.xml b/indra/newview/skins/default/xui/en/floater_settings_picker.xml index 3a26c3b547..8931269fe7 100644 --- a/indra/newview/skins/default/xui/en/floater_settings_picker.xml +++ b/indra/newview/skins/default/xui/en/floater_settings_picker.xml @@ -89,7 +89,7 @@ top="1" right="-4" bottom="-1" - filter_asset_type="settings" /> + filter_asset_types="settings" /> </panel> </layout_panel> <layout_panel name="pnl_combo" diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml index 3a66911389..18c226ed58 100644 --- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml @@ -137,7 +137,29 @@ value="Preview Disabled" word_wrap="true" visible="false" - width="87" /> + width="87" /> + <combo_box + follows="left|top|right" + height="23" + label="Choose Textures, Materials or LIFE!" + layout="topleft" + left="175" + name="textures_material_combo" + top="20" + width="231"> + <combo_box.item + label="Materials & Textures" + name="Materials_Textures" + value="0" /> + <combo_box.item + label="Textures" + name="Textures" + value="1" /> + <combo_box.item + label="Materials" + name="Materials" + value="2" /> + </combo_box> <filter_editor follows="left|top|right" height="23" @@ -145,21 +167,21 @@ layout="topleft" left="175" name="inventory search editor" - top="20" + top="48" width="231" /> - <asset_filtered_inv_panel - allow_multi_select="false" + <asset_filtered_inv_panel + allow_multi_select="false" bg_visible="true" bg_alpha_color="DkGray2" border="false" follows="all" - height="233" + height="195" layout="topleft" left_delta="0" name="inventory panel" top_pad="4" width="231" - filter_asset_type="texture"/> + filter_asset_types="texture|material"/> <check_box height="14" initial_value="false" @@ -218,8 +240,8 @@ multi_select="true" search_column="1" visible="false"> + <column name="icon" label="" width="20" /> <column name="unit_name" label="Name" dynamicwidth="true" /> - <column name="unit_id_HIDDEN" label="ID" width="0" /> </scroll_list> <!-- middle: bake mode --> diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 0abee2ff80..4700488197 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2,7 +2,7 @@ <floater positioning="cascading" legacy_header_height="18" - height="600" + height="651" layout="topleft" bg_opaque_image="Window_NoTitle_Foreground" bg_alpha_image="Window_NoTitle_Background" @@ -68,7 +68,7 @@ </floater.string> <floater.string name="status_selectcount"> - [OBJ_COUNT] objects selected, land impact [LAND_IMPACT] + [OBJ_COUNT] objects selected, land impact [LAND_IMPACT] [secondlife:///app/openfloater/object_weights More info] </floater.string> <floater.string name="status_remaining_capacity"> @@ -763,11 +763,12 @@ font="SansSerifSmall" layout="topleft" left="10" - name="selection_count" + name="selection_faces" top_delta="0" visible="false" width="280"> - </text> + Faces selected: [FACES_STRING] + </text> <text text_color="LtGray_50" type="string" @@ -777,11 +778,10 @@ font="SansSerifSmall" layout="topleft" left="10" - name="remaining_capacity" + name="selection_count" top_pad="0" visible="false" width="280"> - [CAPACITY_STRING] [secondlife:///app/openfloater/object_weights More info] </text> <!-- <text --> <!-- text_color="LtGray_50" --> @@ -820,7 +820,7 @@ width="282"/> <tab_container follows="left|top" - height="410" + height="476" halign="center" left="0" name="Object Info Tabs" @@ -1430,16 +1430,40 @@ even though the user gets a free copy. tool_tip="Causes object to not collide with other objects or avatars" top_pad="0" width="123" /> - <text + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left_delta="0" + name="object_horizontal" + top_pad="10" + width="95" /> + <menu_button + menu_filename="menu_copy_paste_pos.xml" + follows="top|left" + height="11" + image_disabled="ClipboardSmallMenu_Disabled" + image_selected="ClipboardSmallMenu_Press" + image_unselected="ClipboardSmallMenu_Off" + layout="topleft" + left_delta="0" + top_pad="13" + name="clipboard_pos_btn" + tool_tip="Paste options" + width="19"/> + <text type="string" length="1" follows="left|top" height="10" layout="topleft" name="label position" - top_pad="10" + tool_tip="Position (meters)" + left_pad="8" + top_delta="0" width="121"> - Position (meters) + Position (m) </text> <spinner follows="left|top" @@ -1449,12 +1473,12 @@ even though the user gets a free copy. label="X" label_width="10" layout="topleft" - left_delta="0" + left_delta="-27" max_val="512" min_val="-256" name="Pos X" text_enabled_color="1 0 0.3 .7" - top_pad="5" + top_pad="8" width="87" /> <spinner follows="left|top" @@ -1481,21 +1505,36 @@ even though the user gets a free copy. layout="topleft" left_delta="0" max_val="4096" + min_val="-32" name="Pos Z" text_enabled_color="0 0.8 1 .65" top_pad="3" width="87" /> + <menu_button + menu_filename="menu_copy_paste_size.xml" + follows="top|left" + height="11" + image_disabled="ClipboardSmallMenu_Disabled" + image_selected="ClipboardSmallMenu_Press" + image_unselected="ClipboardSmallMenu_Off" + layout="topleft" + left_delta="0" + top_pad="13" + name="clipboard_size_btn" + tool_tip="Paste options" + width="19"/> <text type="string" length="1" follows="left|top" height="10" layout="topleft" - left_delta="0" + left_pad="8" + top_delta="0" name="label size" - top_pad="6" + tool_tip="Size (meters)" width="121"> - Size (meters) + Size (m) </text> <spinner follows="left|top" @@ -1505,12 +1544,12 @@ even though the user gets a free copy. label="X" label_width="10" layout="topleft" - left_delta="0" + left_delta="-27" max_val="64" min_val="0.01" name="Scale X" text_enabled_color="1 1 1 1" - top_pad="5" + top_pad="8" width="87" /> <spinner follows="left|top" @@ -1542,17 +1581,31 @@ even though the user gets a free copy. text_enabled_color="1 1 1 1" top_pad="3" width="87" /> + <menu_button + menu_filename="menu_copy_paste_rot.xml" + follows="top|left" + height="11" + image_disabled="ClipboardSmallMenu_Disabled" + image_selected="ClipboardSmallMenu_Press" + image_unselected="ClipboardSmallMenu_Off" + layout="topleft" + left_delta="0" + top_pad="13" + name="clipboard_rot_btn" + tool_tip="Paste options" + width="19"/> <text type="string" length="1" follows="left|top" height="10" layout="topleft" - left_delta="0" + left_pad="8" + top_delta="0" name="label rotation" - top_pad="10" + tool_tip="Rotation (degrees)" width="121"> - Rotation (degrees) + Rotation (°) </text> <spinner decimal_digits="2" @@ -1563,12 +1616,12 @@ even though the user gets a free copy. label="X" label_width="10" layout="topleft" - left_delta="0" + left_delta="-27" max_val="9999" min_val="-9999" name="Rot X" text_enabled_color="1 1 1 1" - top_pad="5" + top_pad="8" width="87" /> <spinner decimal_digits="2" @@ -1614,13 +1667,23 @@ even though the user gets a free copy. width="150"> Prim Type </text>--> + + <view_border + bevel_style="none" + follows="top|left" + layout="topleft" + name="object_vertical" + left="117" + top="6" + height="500" + width="0"/> <combo_box height="19" layout="topleft" name="comboBaseType" top="6" left="125" - width="150"> + width="125"> <combo_box.item label="Box" name="Box" @@ -1654,13 +1717,26 @@ even though the user gets a free copy. name="Sculpted" value="Sculpted" /> </combo_box> + <menu_button + menu_filename="menu_copy_paste_object.xml" + follows="top|left" + height="15" + image_disabled="ClipboardMenu_Disabled" + image_selected="ClipboardMenu_Press" + image_unselected="ClipboardMenu_Off" + layout="topleft" + left_pad="8" + top_delta="2" + name="clipboard_obj_params_btn" + tool_tip="Paste options" + width="22"/> <text type="string" length="1" follows="left|top" height="10" layout="topleft" - left_delta="0" + left="125" name="text cut" top_pad="5" width="150"> @@ -1700,7 +1776,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="text hollow" - top_pad="6" + top_pad="7" width="68"> Hollow </text> @@ -1748,7 +1824,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="Hollow Shape" - top_pad="4" + top_pad="7" width="150"> Hollow Shape </text> @@ -1784,7 +1860,7 @@ even though the user gets a free copy. layout="topleft" left_delta="0" name="text twist" - top_pad="5" + top_pad="7" width="150"> Twist (begin/end) </text> @@ -1826,12 +1902,12 @@ even though the user gets a free copy. layout="topleft" left="125" name="scale_taper" - top_pad="3" + top_pad="7" width="150"> Taper </text> <text - visible="false" + visible="false" type="string" length="1" follows="left|top" @@ -1879,7 +1955,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="text topshear" - top_pad="3" + top_pad="5" width="141"> Top Shear </text> @@ -1922,12 +1998,12 @@ even though the user gets a free copy. layout="topleft" left="125" name="advanced_cut" - top_pad="3" + top_pad="7" width="150"> Profile Cut (begin/end) </text> <text - visible="false" + visible="false" type="string" length="1" follows="left|top" @@ -1986,7 +2062,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="text taper2" - top_pad="3" + top_pad="7" width="150"> Taper </text> @@ -2029,7 +2105,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="text radius delta" - top_pad="2" + top_pad="7" width="78"> Radius </text> @@ -2157,6 +2233,19 @@ even though the user gets a free copy. <panel.string name="None">None</panel.string> <panel.string name="Prim">Prim</panel.string> <panel.string name="Convex Hull">Convex Hull</panel.string> + <menu_button + menu_filename="menu_copy_paste_features.xml" + follows="top|left" + height="15" + image_disabled="ClipboardMenu_Disabled" + image_selected="ClipboardMenu_Press" + image_unselected="ClipboardMenu_Off" + layout="topleft" + left="258" + top="8" + name="clipboard_features_params_btn" + tool_tip="Paste options" + width="22"/> <text type="string" length="1" @@ -2309,6 +2398,15 @@ even though the user gets a free copy. name="FlexForceZ" top_pad="4" width="128" /> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="8" + name="object_horizontal" + top_pad="10" + width="278" /> <check_box height="16" @@ -2317,7 +2415,7 @@ even though the user gets a free copy. left="10" name="Light Checkbox Ctrl" tool_tip="Causes object to emit light" - top_pad="15" + top_pad="8" width="60" /> <color_swatch can_apply_immediately="true" @@ -2344,6 +2442,19 @@ even though the user gets a free copy. name="light texture control" tool_tip="Click to choose a projection image (only has effect with deferred rendering enabled)" width="32" /> + <menu_button + menu_filename="menu_copy_paste_light.xml" + follows="top|left" + height="15" + image_disabled="ClipboardMenu_Disabled" + image_selected="ClipboardMenu_Press" + image_unselected="ClipboardMenu_Off" + layout="topleft" + left="258" + top_delta="0" + name="clipboard_light_params_btn" + tool_tip="Paste options" + width="22"/> <spinner follows="left|top" height="19" @@ -2353,7 +2464,7 @@ even though the user gets a free copy. layout="topleft" left="10" name="Light Intensity" - top_pad="3" + top_pad="26" width="128" /> <spinner bottom_delta="0" decimal_digits="3" @@ -2420,7 +2531,70 @@ even though the user gets a free copy. mouse_opaque="true" name="Light Ambiance" width="120" /> - <text + <check_box + height="16" + label="Reflection Probe" + layout="topleft" + left="10" + name="Reflection Probe" + tool_tip="Adjusts how objects within this volume receive reflections when PBR is enabled" + top_pad="10" + width="60" /> + <combo_box + height="19" + top_delta="0" + left="144" + follows="left|top" + name="Probe Volume Type" + tool_tip="Choose the probe influence volume" + width="108"> + <combo_box.item + label="Sphere" + name="Sphere" + value="Sphere" /> + <combo_box.item + label="Box" + name="Box" + value="Box"/> + </combo_box> + <check_box + height="16" + label="Dynamic" + layout="topleft" + left="10" + name="Probe Dynamic" + tool_tip="When enabled, Avatars will appear in reflections within this probe's influence volume." + bottom_delta="19" + width="60" /> + <spinner bottom_delta="19" + decimal_digits="3" + follows="left|top" + height="16" + increment="0.05" + initial_value="0" + label="Ambiance" + label_width="55" + left="10" + max_val="1" + min_val="0" + mouse_opaque="true" + name="Probe Ambiance" + width="120" /> + <spinner bottom_delta="0" + decimal_digits="3" + follows="left|top" + height="16" + increment="0.05" + initial_value="0" + label="Near Clip" + label_width="55" + left="144" + max_val="1024" + min_val="0" + mouse_opaque="true" + name="Probe Near Clip" + width="120" /> + <text type="string" length="1" follows="left|top" @@ -2575,7 +2749,7 @@ even though the user gets a free copy. border_visible="true" bevel_style="in" follows="left|top|right" - height="325" + height="387" layout="topleft" left="10" name="contents_inventory" diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml index 83407069d2..45e11fc836 100644 --- a/indra/newview/skins/default/xui/en/floater_world_map.xml +++ b/indra/newview/skins/default/xui/en/floater_world_map.xml @@ -14,6 +14,31 @@ single_instance="true" title="WORLD MAP" width="650"> + <string + name="collapse_icon" + value="map_ui_collapse_icon.png"/> + <string + name="expand_icon" + value="map_ui_expand_icon.png"/> + <string + name="collapse_tooltip" + value="Hide map controls"/> + <string + name="expand_tooltip" + value="Show map controls"/> + <layout_stack + animate="false" + follows="all" + name="floater_map_stack" + tab_group="1" + top="16" + left="0" + right="-1" + bottom="-1"> + <layout_panel + name="map_lp" + width="385" + height="575"> <panel filename="panel_world_map.xml" follows="all" @@ -21,17 +46,48 @@ layout="topleft" left="10" name="objects_mapview" - top="25" + top="6" width="375" /> + <panel + follows="top|right" + height="30" + layout="topleft" + left_pad="-29" + name="expand_btn_panel" + background_visible="true" + bg_opaque_color="FloaterFocusBackgroundColor" + bg_alpha_color="FloaterDefaultBackgroundColor" + background_opaque="true" + tool_tip="Hide map controls" + top="350" + width="30"> + <icon + follows="top|right" + height="16" + width="16" + top="7" + left="7" + scale_image="false" + image_name="map_ui_collapse_icon.png" + layout="topleft" + mouse_opaque="true" + name="expand_collapse_icon" + tool_tip="Hide map controls" /> + </panel> + </layout_panel> + <layout_panel + height="575" + width="265" + expanded_min_dim="265" + name="controls_lp"> <panel - name="layout_panel_1" - height="22" - width="238" - follows="right|top" - top="25" - left_pad="5" - background_visible="true" - bg_alpha_color="DkGray2"> + name="layout_panel_1" + height="22" + width="238" + follows="right|top" + top="6" + background_visible="true" + bg_alpha_color="DkGray2"> <text text_color="White" font="SansSerifLarge" @@ -43,17 +99,17 @@ layout="topleft" left="15" name="events_label" - top="3" width="215"> Legend </text> </panel> -<panel - follows="right|top" - height="126" - top_pad="0" - width="238" - name="layout_panel_2"> + <panel + follows="right|top" + height="126" + top_pad="4" + width="238" + left="1" + name="layout_panel_2"> <button follows="right|top" height="22" @@ -690,4 +746,6 @@ show_text="false" width="200" /> </panel> + </layout_panel> + </layout_stack> </floater> diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml index 9885e37cea..842184de88 100644 --- a/indra/newview/skins/default/xui/en/main_view.xml +++ b/indra/newview/skins/default/xui/en/main_view.xml @@ -8,6 +8,16 @@ tab_stop="false" name="main_view" width="1024"> + + <!-- At the moment layout_stack is not an LLUICtrl, + but Tab requires focus_root to function and focus_root + functionality is implemented in LLUICtrl --> + <panel follows="all" + height="768" + name="menu_tab_wrapper" + mouse_opaque="false" + focus_root="true" + top="0"> <layout_stack border_size="0" follows="all" mouse_opaque="false" @@ -18,12 +28,12 @@ <layout_panel mouse_opaque="true" follows="left|right|top" name="status_bar_container" - tab_stop="false" height="19" left="0" top="0" width="1024" auto_resize="false" + default_tab_group="1" visible="true"> <view mouse_opaque="false" follows="all" @@ -31,13 +41,13 @@ left="0" top="0" width="1024" + tab_group="1" height="19"/> </layout_panel> <layout_panel auto_resize="false" height="34" mouse_opaque="false" name="nav_bar_container" - tab_stop="false" width="1024" visible="false"/> <layout_panel auto_resize="true" @@ -99,6 +109,7 @@ tab_stop="false"/> </layout_panel> </layout_stack> + </panel> <!--menu_tab_wrapper--> <panel top="0" follows="all" diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml index 26b1c86c53..3b91b9df7a 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml @@ -33,6 +33,13 @@ function="Object.EnableTouch" name="EnableTouch"/> </menu_item_call> + <menu_item_call + label="Show in inventory" + layout="topleft" + name="Show original"> + <menu_item_call.on_click + function="Object.ShowOriginal" /> + </menu_item_call> <menu_item_separator layout="topleft" /> diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml new file mode 100644 index 0000000000..4c12180daf --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Color Menu"> + <menu_item_call + label="Copy" + layout="topleft" + name="params_copy" + visible="true"> + <on_click function="PanelFace.menuDoToSelected" parameter="color_copy" /> + </menu_item_call> + <menu_item_call + label="Paste" + layout="topleft" + name="params_paste" + visible="true"> + <on_click function="PanelFace.menuDoToSelected" parameter="color_paste" /> + <on_enable function="PanelFace.menuEnable" parameter="color_paste" /> + </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml new file mode 100644 index 0000000000..4823d74a26 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Features Menu"> + <menu_item_call + label="Copy" + layout="topleft" + name="params_copy" + visible="true"> + <on_click function="PanelVolume.menuDoToSelected" parameter="features_copy" /> + </menu_item_call> + <menu_item_call + label="Paste" + layout="topleft" + name="params_paste" + visible="true"> + <on_click function="PanelVolume.menuDoToSelected" parameter="features_paste" /> + <on_enable function="PanelVolume.menuEnable" parameter="features_paste" /> + </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml new file mode 100644 index 0000000000..5de23dfee3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Light Menu"> + <menu_item_call + label="Copy" + layout="topleft" + name="params_copy" + visible="true"> + <on_click function="PanelVolume.menuDoToSelected" parameter="light_copy" /> + </menu_item_call> + <menu_item_call + label="Paste" + layout="topleft" + name="params_paste" + visible="true"> + <on_click function="PanelVolume.menuDoToSelected" parameter="light_paste" /> + <on_enable function="PanelVolume.menuEnable" parameter="light_paste" /> + </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml new file mode 100644 index 0000000000..bdc4537a9d --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Object Menu"> + <menu_item_call + label="Copy" + layout="topleft" + name="params_copy" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="params_copy" /> + </menu_item_call> + <menu_item_call + label="Paste" + layout="topleft" + name="params_paste" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="params_paste" /> + <on_enable function="PanelObject.menuEnable" parameter="params_paste" /> + </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml new file mode 100644 index 0000000000..3ea95b281f --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Position Menu"> + <menu_item_call + label="Copy all" + layout="topleft" + name="psr_copy" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" /> + <on_enable function="PanelObject.menuEnable" parameter="psr_copy" /> + </menu_item_call> + <menu_item_call + label="Copy position" + layout="topleft" + name="pos_copy" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="pos_copy" /> + </menu_item_call> + <menu_item_call + label="Paste all" + layout="topleft" + name="psr_paste" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" /> + <on_enable function="PanelObject.menuEnable" parameter="psr_paste" /> + </menu_item_call> + <menu_item_call + label="Paste position" + layout="topleft" + name="pos_paste" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="pos_paste" /> + <on_enable function="PanelObject.menuEnable" parameter="pos_paste" /> + </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml new file mode 100644 index 0000000000..06ce80f897 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Rotation Menu"> + <menu_item_call + label="Copy all" + layout="topleft" + name="psr_copy" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" /> + <on_enable function="PanelObject.menuEnable" parameter="rot_paste" /> + </menu_item_call> + <menu_item_call + label="Copy rotation" + layout="topleft" + name="rot_copy" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="rot_copy" /> + </menu_item_call> + <menu_item_call + label="Paste all" + layout="topleft" + name="psr_paste" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" /> + <on_enable function="PanelObject.menuEnable" parameter="psr_paste" /> + </menu_item_call> + <menu_item_call + label="Paste rotation" + layout="topleft" + name="rot_paste" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="rot_paste" /> + <on_enable function="PanelObject.menuEnable" parameter="rot_paste" /> + </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml new file mode 100644 index 0000000000..7082a0e65b --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Size Menu"> + <menu_item_call + label="Copy all" + layout="topleft" + name="psr_copy" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="psr_copy" /> + <on_enable function="PanelObject.menuEnable" parameter="psr_copy" /> + </menu_item_call> + <menu_item_call + label="Copy size" + layout="topleft" + name="size_copy" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="size_copy" /> + </menu_item_call> + <menu_item_call + label="Paste all" + layout="topleft" + name="psr_paste" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="psr_paste" /> + <on_enable function="PanelObject.menuEnable" parameter="psr_paste" /> + </menu_item_call> + <menu_item_call + label="Paste size" + layout="topleft" + name="size_paste" + visible="true"> + <on_click function="PanelObject.menuDoToSelected" parameter="size_paste" /> + <on_enable function="PanelObject.menuEnable" parameter="size_paste" /> + </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml new file mode 100644 index 0000000000..f358affc23 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<toggleable_menu + layout="topleft" + name="Copy Paste Texture Menu"> + <menu_item_call + label="Copy" + layout="topleft" + name="params_copy" + visible="true"> + <on_click function="PanelFace.menuDoToSelected" parameter="texture_copy" /> + </menu_item_call> + <menu_item_call + label="Paste" + layout="topleft" + name="params_paste" + visible="true"> + <on_click function="PanelFace.menuDoToSelected" parameter="texture_paste" /> + <on_enable function="PanelFace.menuEnable" parameter="texture_paste" /> + </menu_item_call> +</toggleable_menu> + diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 78ca170813..c7c1e1d75a 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -143,264 +143,6 @@ function="Inventory.EmptyLostAndFound" parameter="rename" /> </menu_item_call> - <menu_item_call - label="New Folder" - layout="topleft" - name="New Folder"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="category" /> - </menu_item_call> - <menu_item_call - label="New Outfit" - layout="topleft" - name="New Outfit"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="outfit" /> - </menu_item_call> - <menu_item_call - label="New Script" - layout="topleft" - name="New Script"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="lsl" /> - </menu_item_call> - <menu_item_call - label="New Notecard" - layout="topleft" - name="New Note"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="notecard" /> - </menu_item_call> - <menu_item_call - label="New Gesture" - layout="topleft" - name="New Gesture"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="gesture" /> - </menu_item_call> - <menu - label="New Clothes" - layout="topleft" - name="New Clothes"> - <menu_item_call - label="New Shirt" - layout="topleft" - name="New Shirt"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="shirt" /> - </menu_item_call> - <menu_item_call - label="New Pants" - layout="topleft" - name="New Pants"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="pants" /> - </menu_item_call> - <menu_item_call - label="New Shoes" - layout="topleft" - name="New Shoes"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="shoes" /> - </menu_item_call> - <menu_item_call - label="New Socks" - layout="topleft" - name="New Socks"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="socks" /> - </menu_item_call> - <menu_item_call - label="New Jacket" - layout="topleft" - name="New Jacket"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="jacket" /> - </menu_item_call> - <menu_item_call - label="New Skirt" - layout="topleft" - name="New Skirt"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="skirt" /> - </menu_item_call> - <menu_item_call - label="New Gloves" - layout="topleft" - name="New Gloves"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="gloves" /> - </menu_item_call> - <menu_item_call - label="New Undershirt" - layout="topleft" - name="New Undershirt"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="undershirt" /> - </menu_item_call> - <menu_item_call - label="New Underpants" - layout="topleft" - name="New Underpants"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="underpants" /> - </menu_item_call> - <menu_item_call - label="New Alpha Mask" - layout="topleft" - name="New Alpha Mask"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="alpha" /> - </menu_item_call> - <menu_item_call - label="New Tattoo" - layout="topleft" - name="New Tattoo"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="tattoo" /> - </menu_item_call> - <menu_item_call - label="New Universal" - layout="topleft" - name="New Universal"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="universal" /> - </menu_item_call> - <menu_item_call - label="New Physics" - layout="topleft" - name="New Physics"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="physics" /> - </menu_item_call> - </menu> - <menu - label="New Body Parts" - layout="topleft" - name="New Body Parts"> - <menu_item_call - label="New Shape" - layout="topleft" - name="New Shape"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="shape" /> - </menu_item_call> - <menu_item_call - label="New Skin" - layout="topleft" - name="New Skin"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="skin" /> - </menu_item_call> - <menu_item_call - label="New Hair" - layout="topleft" - name="New Hair"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="hair" /> - </menu_item_call> - <menu_item_call - label="New Eyes" - layout="topleft" - name="New Eyes"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="eyes" /> - </menu_item_call> - </menu> - <menu - label="New Settings" - layout="topleft" - name="New Settings"> - <menu_item_call - label="New Sky" - layout="topleft" - name="New Sky"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="sky"/> - <menu_item_call.on_enable - function="Inventory.EnvironmentEnabled" /> - </menu_item_call> - <menu_item_call - label="New Water" - layout="topleft" - name="New Water"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="water"/> - <menu_item_call.on_enable - function="Inventory.EnvironmentEnabled" /> - </menu_item_call> - <menu_item_call - label="New Day Cycle" - layout="topleft" - name="New Day Cycle"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="daycycle"/> - <menu_item_call.on_enable - function="Inventory.EnvironmentEnabled" /> - </menu_item_call> - </menu> - <menu - label="Use as default for" - layout="topleft" - name="upload_def"> - <menu_item_call - label="Image uploads" - layout="topleft" - name="Image uploads"> - <menu_item_call.on_click - function="Inventory.FileUploadLocation" - parameter="texture" /> - </menu_item_call> - <menu_item_call - label="Sound uploads" - layout="topleft" - name="Sound uploads"> - <menu_item_call.on_click - function="Inventory.FileUploadLocation" - parameter="sound" /> - </menu_item_call> - <menu_item_call - label="Animation uploads" - layout="topleft" - name="Animation uploads"> - <menu_item_call.on_click - function="Inventory.FileUploadLocation" - parameter="animation" /> - </menu_item_call> - <menu_item_call - label="Model uploads" - layout="topleft" - name="Model uploads"> - <menu_item_call.on_click - function="Inventory.FileUploadLocation" - parameter="model" /> - </menu_item_call> - </menu> <menu label="Change Type" layout="topleft" @@ -683,6 +425,275 @@ parameter="delete_system_folder" /> </menu_item_call> <menu_item_separator + layout="topleft" + name="Create Separator" /> + <menu_item_call + label="New Folder" + layout="topleft" + name="New Folder"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="category" /> + </menu_item_call> + <menu_item_call + label="New Outfit" + layout="topleft" + name="New Outfit"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="outfit" /> + </menu_item_call> + <menu_item_call + label="New Script" + layout="topleft" + name="New Script"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="lsl" /> + </menu_item_call> + <menu_item_call + label="New Notecard" + layout="topleft" + name="New Note"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="notecard" /> + </menu_item_call> + <menu_item_call + label="New Gesture" + layout="topleft" + name="New Gesture"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="gesture" /> + </menu_item_call> + <menu_item_call + label="New Material" + layout="topleft" + name="New Material"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="material" /> + </menu_item_call> + <menu + label="New Clothes" + layout="topleft" + name="New Clothes"> + <menu_item_call + label="New Shirt" + layout="topleft" + name="New Shirt"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="shirt" /> + </menu_item_call> + <menu_item_call + label="New Pants" + layout="topleft" + name="New Pants"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="pants" /> + </menu_item_call> + <menu_item_call + label="New Shoes" + layout="topleft" + name="New Shoes"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="shoes" /> + </menu_item_call> + <menu_item_call + label="New Socks" + layout="topleft" + name="New Socks"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="socks" /> + </menu_item_call> + <menu_item_call + label="New Jacket" + layout="topleft" + name="New Jacket"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="jacket" /> + </menu_item_call> + <menu_item_call + label="New Skirt" + layout="topleft" + name="New Skirt"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="skirt" /> + </menu_item_call> + <menu_item_call + label="New Gloves" + layout="topleft" + name="New Gloves"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="gloves" /> + </menu_item_call> + <menu_item_call + label="New Undershirt" + layout="topleft" + name="New Undershirt"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="undershirt" /> + </menu_item_call> + <menu_item_call + label="New Underpants" + layout="topleft" + name="New Underpants"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="underpants" /> + </menu_item_call> + <menu_item_call + label="New Alpha Mask" + layout="topleft" + name="New Alpha Mask"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="alpha" /> + </menu_item_call> + <menu_item_call + label="New Tattoo" + layout="topleft" + name="New Tattoo"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="tattoo" /> + </menu_item_call> + <menu_item_call + label="New Universal" + layout="topleft" + name="New Universal"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="universal" /> + </menu_item_call> + <menu_item_call + label="New Physics" + layout="topleft" + name="New Physics"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="physics" /> + </menu_item_call> + </menu> + <menu + label="New Body Parts" + layout="topleft" + name="New Body Parts"> + <menu_item_call + label="New Shape" + layout="topleft" + name="New Shape"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="shape" /> + </menu_item_call> + <menu_item_call + label="New Skin" + layout="topleft" + name="New Skin"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="skin" /> + </menu_item_call> + <menu_item_call + label="New Hair" + layout="topleft" + name="New Hair"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="hair" /> + </menu_item_call> + <menu_item_call + label="New Eyes" + layout="topleft" + name="New Eyes"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="eyes" /> + </menu_item_call> + </menu> + <menu + label="New Settings" + layout="topleft" + name="New Settings"> + <menu_item_call + label="New Sky" + layout="topleft" + name="New Sky"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="sky"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + </menu_item_call> + <menu_item_call + label="New Water" + layout="topleft" + name="New Water"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="water"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + </menu_item_call> + <menu_item_call + label="New Day Cycle" + layout="topleft" + name="New Day Cycle"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="daycycle"/> + <menu_item_call.on_enable + function="Inventory.EnvironmentEnabled" /> + </menu_item_call> + </menu> + <menu + label="Use as default for" + layout="topleft" + name="upload_def"> + <menu_item_call + label="Image uploads" + layout="topleft" + name="Image uploads"> + <menu_item_call.on_click + function="Inventory.FileUploadLocation" + parameter="texture" /> + </menu_item_call> + <menu_item_call + label="Sound uploads" + layout="topleft" + name="Sound uploads"> + <menu_item_call.on_click + function="Inventory.FileUploadLocation" + parameter="sound" /> + </menu_item_call> + <menu_item_call + label="Animation uploads" + layout="topleft" + name="Animation uploads"> + <menu_item_call.on_click + function="Inventory.FileUploadLocation" + parameter="animation" /> + </menu_item_call> + <menu_item_call + label="Model uploads" + layout="topleft" + name="Model uploads"> + <menu_item_call.on_click + function="Inventory.FileUploadLocation" + parameter="model" /> + </menu_item_call> + </menu> + <menu_item_separator layout="topleft" /> <menu_item_separator layout="topleft" /> @@ -912,6 +923,25 @@ function="Inventory.DoToSelected" parameter="apply_settings_parcel" /> </menu_item_call> + <menu_item_separator + layout="topleft" + name="Subfolder Separator" /> + <menu_item_call + label="Create folder from selected" + layout="topleft" + name="New folder from selected"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="new_folder_from_selected" /> + </menu_item_call> + <menu_item_call + label="Ungroup folder items" + layout="topleft" + name="Ungroup folder items"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="ungroup_folder_items" /> + </menu_item_call> <menu_item_separator layout="topleft" name="Marketplace Separator" /> diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index 3385a29a6c..0e193521a3 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -97,6 +97,14 @@ function="Inventory.DoCreate" parameter="gesture" /> </menu_item_call> + <menu_item_call + label="New Material" + layout="topleft" + name="New Material"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="material" /> + </menu_item_call> <menu height="175" label="New Clothes" diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 85c20268d0..cf99240908 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -471,7 +471,7 @@ layout="topleft" name="Reset Skeleton And Animations"> <menu_item_call.on_click - function="Avatar.ResetSkeletonAndAnimations" /> + function="Avatar.ResetSelfSkeletonAndAnimations" /> </menu_item_call> <menu_item_call label="Attachment scripts..." @@ -1417,6 +1417,15 @@ function="World.EnvPreset" function="Tools.SelectOnlyMovableObjects" parameter="movable" /> </menu_item_check> + <menu_item_check + label="Select Invisible Objects" + name="Select Invisible Objects"> + <menu_item_check.on_check + control="SelectInvisibleObjects" /> + <menu_item_check.on_click + function="Tools.SelectInvisibleObjects" + parameter="invisible" /> + </menu_item_check> <menu_item_check label="Select By Surrounding" name="Select By Surrounding"> @@ -1574,6 +1583,16 @@ function="World.EnvPreset" <menu_item_call.on_visible function="File.VisibleUploadModel"/> </menu_item_call> + <menu_item_call + label="Material..." + layout="topleft" + name="Upload Material"> + <menu_item_call.on_click + function="File.UploadMaterial" + parameter="" /> + <menu_item_call.on_enable + function="File.EnableUploadMaterial" /> + </menu_item_call> <menu_item_call label="Bulk..." layout="topleft" @@ -1586,7 +1605,15 @@ function="World.EnvPreset" parameter="" /> </menu_item_call> </menu> - <menu_item_separator/> + <menu_item_call + label="Material Editor" + name="material_editor_menu_item"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="material_editor" /> + </menu_item_call> + + <menu_item_separator/> <menu_item_call enabled="false" label="Undo" @@ -2898,6 +2925,16 @@ function="World.EnvPreset" parameter="lights" /> </menu_item_check> <menu_item_check + label="Reflection Probes" + name="Reflection Probes"> + <menu_item_check.on_check + function="Advanced.CheckInfoDisplay" + parameter="reflection probes" /> + <menu_item_check.on_click + function="Advanced.ToggleInfoDisplay" + parameter="reflection probes" /> + </menu_item_check> + <menu_item_check label="Particles" name="Particles"> <menu_item_check.on_check @@ -3069,18 +3106,6 @@ function="World.EnvPreset" <menu_item_separator /> <menu_item_check - label="Advanced Lighting Model" - name="Advanced Lighting Model"> - <menu_item_check.on_check - function="CheckControl" - parameter="RenderDeferred" /> - <menu_item_check.on_click - function="ToggleControl" - parameter="RenderDeferred" /> - <menu_item_check.on_enable - function="Advanced.EnableRenderDeferred" /> - </menu_item_check> - <menu_item_check label=" Shadows from Sun/Moon/Projectors" name="Shadows from Sun/Moon/Projectors"> <menu_item_check.on_check @@ -3107,14 +3132,14 @@ function="World.EnvPreset" <menu_item_separator /> <menu_item_check - label="Debug GL" + label="Start Debug GL on next run" name="Debug GL"> <menu_item_check.on_check function="CheckControl" - parameter="RenderDebugGL" /> + parameter="RenderDebugGLSession" /> <menu_item_check.on_click function="ToggleControl" - parameter="RenderDebugGL" /> + parameter="RenderDebugGLSession" /> </menu_item_check> <menu_item_check label="Debug Pipeline" @@ -3236,6 +3261,13 @@ function="World.EnvPreset" function="ToggleControl" parameter="RenderHoverGlowEnable" /> </menu_item_check> + <menu_item_call + enabled="true" + label="Rebuild Reflection Probes" + name="Rebuild Reflection Probes"> + <menu_item_call.on_click + function="Develop.RebuildReflectionProbes" /> + </menu_item_call> <menu_item_separator /> <menu_item_call diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index aa93601669..c618c5bf32 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6764,6 +6764,22 @@ You don't have permission to view this notecard. <notification icon="notifytip.tga" + name="MaterialMissing" + type="notifytip"> + Material is missing from database. + <tag>fail</tag> + </notification> + + <notification + icon="notifytip.tga" + name="MaterialNoPermissions" + type="notifytip"> + You don't have permission to view this material. + <tag>fail</tag> + </notification> + + <notification + icon="notifytip.tga" name="RezItemNoPermissions" type="notifytip"> Insufficient permissions to rez object. @@ -6795,6 +6811,15 @@ Please try again. <notification icon="notifytip.tga" + name="UnableToLoadMaterial" + type="notifytip"> + Unable to load material. + Please try again. + <tag>fail</tag> + </notification> + + <notification + icon="notifytip.tga" name="ScriptMissing" type="notifytip"> Script is missing from database. @@ -9025,7 +9050,64 @@ Unable to upload texture. [REASON] <tag>fail</tag> </notification> - + + <notification + icon="alertmodal.tga" + name="CannotUploadMaterial" + type="alertmodal"> +There was a problem uploading the file + <tag>fail</tag> + </notification> + + <notification + icon="alertmodal.tga" + label="Save Material" + name="SaveMaterialAs" + type="alertmodal"> + <unique/> + Name this material: + <tag>confirm</tag> + <form name="form"> + <input name="message" type="text"> + [DESC] + </input> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> + + <notification + icon="alertmodal.tga" + name="InvalidMaterialName" + type="alertmodal"> +Please enter a non-empty name + <tag>fail</tag> + </notification> + + <notification + icon="alertmodal.tga" + name="UsavedMaterialChanges" + type="alertmodal"> + You have unsaved changes. + <form name="form"> + <button + index="0" + name="discard" + text="Discard changes"/> + <button + index="1" + name="keep" + text="Keep editing"/> + </form> + </notification> + <notification icon="alertmodal.tga" name="LivePreviewUnavailable" @@ -9040,6 +9122,29 @@ We cannot display a preview of this texture because it is no-copy and/or no-tran <notification icon="alertmodal.tga" + name="FacePasteFailed" + type="alertmodal"> +Paste failed. [REASON] + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="FacePasteTexturePermissions" + type="alertmodal"> + You applied a texture with limited permissions, object will inherit permissions from texture. + <usetemplate + ignoretext="Paste: You applied a texture with limited permissions" + name="notifyignore"/> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="ConfirmLeaveCall" type="alertmodal"> Are you sure you want to leave this call? @@ -9699,6 +9804,15 @@ Attempt cancelled. <notification icon="alertmodal.tga" + name="LocalGLTFVerifyFail" + persist="true" + type="notify"> +Attempted to add an invalid or unreadable GLTF material [FNAME] which could not be opened or decoded. +Attempt cancelled. + </notification> + + <notification + icon="alertmodal.tga" name="PathfindingReturnMultipleItems" type="alertmodal"> You are returning [NUM_ITEMS] items. Are you sure you want to continue? @@ -11640,7 +11754,7 @@ This Region does not support environmental settings. <notification icon="alertmodal.tga" - label="Save Outfit" + label="Save Environmental Settings" name="SaveSettingAs" type="alertmodal"> <unique/> @@ -11819,4 +11933,44 @@ Unpacking: [UNPACK_TIME]s [USIZE]KB </form> </notification> + <notification + icon="alertmodal.tga" + label="Create subfolder" + name="CreateSubfolder" + type="alertmodal"> + <unique/> + Name the new folder: + <tag>confirm</tag> + <form name="form"> + <input name="message" type="text"> + [DESC] + </input> + <button + default="true" + index="0" + name="OK" + text="OK"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> + <notification + icon="alertmodal.tga" + name="SameFolderRequired" + type="alert"> + Selected items must be in the same folder. + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + +<notification + icon="notifytip.tga" + name="MaterialCreated" + type="notifytip"> +Material successfully created. Asset ID: [ASSET_ID] +</notification> </notifications> diff --git a/indra/newview/skins/default/xui/en/panel_group_general.xml b/indra/newview/skins/default/xui/en/panel_group_general.xml index e34335a2af..5eafb5cdf1 100644 --- a/indra/newview/skins/default/xui/en/panel_group_general.xml +++ b/indra/newview/skins/default/xui/en/panel_group_general.xml @@ -95,6 +95,7 @@ Hover your mouse over the options for more help. layout="topleft" max_length="511" name="charter" + parse_urls="true" top="105" right="-4" bg_readonly_color="DkGray2" diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index ade004f9d0..3aba80909a 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -145,7 +145,7 @@ follows="left|top" font="SansSerifMedium" text_color="EmphasisColor" - height="16" + height="24" left="408" bottom_delta="0" label="Remember password" diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml index 5568ccb792..d36c83d292 100644 --- a/indra/newview/skins/default/xui/en/panel_login_first.xml +++ b/indra/newview/skins/default/xui/en/panel_login_first.xml @@ -98,7 +98,7 @@ auto_resize="false" follows="left|right|top" name="widget_container" - width="532" + width="730" left="0" top="0" height="80"> @@ -106,7 +106,7 @@ allow_text_entry="true" follows="left|bottom" height="32" - left="2" + left="42" label="Username" combo_editor.font="SansSerifLarge" max_chars="128" @@ -126,7 +126,7 @@ follows="left|top" width="200" height="32" - left="220" + left="262" max_length_chars="16" name="password_edit" label="Password" @@ -145,42 +145,58 @@ label_color="White" font="SansSerifLarge" name="connect_btn" - left="432" - width="100" + left_pad="15" + width="120" height="32" top="0" /> + <text + follows="left|top" + font="SansSerifLarge" + font.style="BOLD" + text_color="EmphasisColor" + height="34" + name="sign_up_text" + left_pad="10" + top="0" + width="200" + valign="center"> + Sign up + </text> <check_box - control_name="RememberPassword" follows="left|top" font="SansSerifLarge" - left="0" + left="42" top="32" height="24" label="Remember me" + word_wrap="down" check_button.bottom="3" - name="remember_check" - width="145" /> - <text + name="remember_name" + tool_tip="Already remembered user can be forgotten from Me > Preferences > Advanced > Remembered Usernames." + width="198" /> + <check_box + control_name="RememberPassword" follows="left|top" font="SansSerifLarge" text_color="EmphasisColor" - height="16" - name="forgot_password_text" - left="219" - top="34" - width="200"> - Forgotten password - </text> + height="24" + left="262" + bottom_delta="0" + label="Remember password" + word_wrap="down" + check_button.bottom="3" + name="remember_password" + width="198" /> <text follows="left|top" font="SansSerifLarge" text_color="EmphasisColor" height="16" - name="sign_up_text" - left="432" + name="forgot_password_text" + left="492" top="34" width="200"> - Sign up + Forgotten password </text> </layout_panel> <layout_panel @@ -216,24 +232,17 @@ auto_resize="false" follows="left|right|top" name="images_container" - width="832" + width="675" left="0" top="0" height="500"> <icon - height="400" - width="400" - image_name="first_login_image_left" + height="450" + width="675" + image_name="first_login_image" left="0" name="image_left" top="0" /> - <icon - height="400" - width="400" - image_name="first_login_image_right" - left_pad="32" - name="image_right" - top="0" /> </layout_panel> <layout_panel height="100" diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index 1c9aa1eb83..b44c19810b 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -4,7 +4,6 @@ background_visible="true" bg_opaque_color="MouseGray" follows="left|top|right" - focus_root="true" height="34" layout="topleft" name="navigation_bar" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 5aff7a5127..908ddd32b5 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -232,33 +232,19 @@ </text> <check_box - control_name="WindLightUseAtmosShaders" + control_name="RenderPBR" height="16" initial_value="true" - label="Atmospheric shaders" + label="Physically Based Rendering" layout="topleft" left="30" - name="WindLightUseAtmosShaders" - top_delta="24" - width="280"> - <check_box.commit_callback - function="Pref.RenderOptionUpdate" /> - </check_box> - - <check_box - control_name="RenderDeferred" - height="16" - initial_value="true" - label="Advanced Lighting Model" - layout="topleft" - left="30" - name="UseLightShaders" + name="UsePBRShaders" top_delta="24" width="256"> <check_box.commit_callback function="Pref.RenderOptionUpdate" /> </check_box> - + <slider control_name="IndirectMaxComplexity" tool_tip="Controls at what point a visually complex avatar is drawn as a JellyDoll" @@ -274,7 +260,7 @@ max_val="101" name="IndirectMaxComplexity" show_text="false" - top_delta="60" + top_delta="36" width="300"> <slider.commit_callback function="Pref.UpdateIndirectMaxComplexity" diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml index 6f82a0efa1..094be36b01 100644 --- a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml +++ b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml @@ -315,6 +315,29 @@ top_delta="20" width="219" can_edit_text="true"/> + <text + follows="left|top" + height="10" + layout="topleft" + left_delta="-5" + top_delta="25" + width="200"> + Reflection Probe Ambiance: + </text> + <slider + decimal_digits="3" + follows="left|top" + height="16" + increment="0.01" + initial_value="0" + layout="topleft" + left_delta="5" + min_val="0" + max_val="1" + name="probe_ambiance" + top_delta="20" + width="219" + can_edit_text="true"/> </layout_panel> </layout_stack> </layout_panel> diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 9023d68ea9..b711ed0e1c 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -11,7 +11,6 @@ mouse_opaque="false" name="status" top="19" - tab_stop="false" width="1000"> <panel.string name="packet_loss_tooltip"> diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index 90f32ae452..326fb27915 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -2,7 +2,7 @@ <panel border="false" follows="all" - height="420" + height="500" label="Texture" layout="topleft" left="0" @@ -11,6 +11,36 @@ name="Texture" top="0" width="295"> + <panel.string + name="paste_error_face_selection_mismatch"> + When multiple faces are copied, the target object must have the same number of faces selected. + </panel.string> + <panel.string + name="paste_error_object_face_count_mismatch"> + When all faces of an object are copied, the target object must have the same number of faces. + </panel.string> + <panel.string + name="paste_error_inventory_not_found"> + One or more texture not found in inventory. + </panel.string> + <panel.string + name="paste_options"> + Paste options + </panel.string> + + <menu_button + menu_filename="menu_copy_paste_color.xml" + follows="top|left" + height="15" + image_disabled="ClipboardMenu_Disabled" + image_selected="ClipboardMenu_Press" + image_unselected="ClipboardMenu_Off" + layout="topleft" + left="258" + top="8" + name="clipboard_color_params_btn" + tool_tip="Paste options" + width="22"/> <text type="string" length="1" @@ -36,7 +66,7 @@ name="colorswatch" tool_tip="Click to open color picker" top="20" - width="64" /> + width="54" /> <text type="string" length="1" @@ -84,7 +114,7 @@ left_delta="0" name="glow" top_pad="4" - width="80" /> + width="77" /> <check_box height="19" label="Full Bright" @@ -93,13 +123,22 @@ name="checkbox fullbright" top_pad="4" width="81" /> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="8" + name="object_horizontal" + top_pad="4" + width="278" /> <combo_box height="23" layout="topleft" left="10" name="combobox matmedia" - top_pad="5" - width="100"> + top_pad="17" + width="90"> <combo_box.item label="Materials" name="Materials" @@ -113,7 +152,7 @@ control_name="ComboMaterialType" height="50" layout="topleft" - left_pad="20" + left_pad="5" top_delta="-10" width="150" visible = "false" @@ -139,7 +178,20 @@ layout="topleft" top_pad="1" value="2"/> - </radio_group> + </radio_group> + <menu_button + menu_filename="menu_copy_paste_texture.xml" + follows="top|left" + height="15" + image_disabled="ClipboardMenu_Disabled" + image_selected="ClipboardMenu_Press" + image_unselected="ClipboardMenu_Off" + layout="topleft" + left="258" + top_delta="0" + name="clipboard_texture_params_btn" + tool_tip="Paste options" + width="22"/> <check_box control_name="SyncMaterialSettings" follows="top|left" @@ -150,7 +202,7 @@ left="8" name="checkbox_sync_settings" tool_tip="Adjust all maps repeats simultaneously" - top_pad="-16" + top_pad="19" width="160" /> <texture_picker can_apply_immediately="true" @@ -771,14 +823,14 @@ top_delta="16" width="260" /> <button - left="10" - top="222" + follows="left|top" + layout="topleft" + left="9" + top="204" height="20" label="Align" label_selected="Align current texture layers" - layout="topleft" name="button align textures" - top_delta="0" tool_tip="Align current texture layers" width="66" /> <web_browser @@ -793,4 +845,29 @@ height="4" start_url="about:blank" decouple_texture_size="true" /> - </panel> + <button + left="90" + top="227" + height="20" + label="Save as Material" + label_selected="Save current face as a Material" + layout="topleft" + name="button save material" + top_delta="0" + tool_tip="Save material to inventory" + width="110" /> + + <line_editor + enabled="true" + follows="top|left" + height="16" + layout="topleft" + left="7" + label="Material UUID" + name="materialID" + select_on_focus="true" + top="405" + width="200" + tool_tip="UUID for a material asset" + /> +</panel> diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml index 8a3e18707f..1c9d750aa6 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml @@ -459,7 +459,7 @@ label="Price: L$" label_width="73" width="150" - min_val="1" + min_val="0" height="20" max_val="999999999" tool_tip="Object cost." /> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index acb3a720b9..4b094da805 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -69,6 +69,7 @@ Voice Server Version: [VOICE_VERSION] </string> <string name="AboutTraffic">Packets Lost: [PACKETS_LOST,number,0]/[PACKETS_IN,number,0] ([PACKETS_PCT,number,1]%)</string> <string name="AboutTime">[month, datetime, slt] [day, datetime, slt] [year, datetime, slt] [hour, datetime, slt]:[min, datetime, slt]:[second,datetime,slt]</string> + <string name="LocalTime">[month, datetime, local] [day, datetime, local] [year, datetime, local] [hour, datetime, local]:[min, datetime, local]:[second,datetime, local]</string> <string name="ErrorFetchingServerReleaseNotesURL">Error fetching server release notes URL.</string> <string name="BuildConfiguration">Build Configuration</string> @@ -111,7 +112,7 @@ Voice Server Version: [VOICE_VERSION] <string name="CertAllocationFailure">Failed to allocate openssl memory for certificate.</string> <string name="LoginFailedNoNetwork">Network error: Could not establish connection, please check your network connection.</string> - <string name="LoginFailed">Login failed.</string> + <string name="LoginFailedHeader">Login failed.</string> <string name="Quit">Quit</string> <string name="create_account_url">http://join.secondlife.com/?sourceid=[sourceid]</string> @@ -125,6 +126,8 @@ http://secondlife.com/download For more information, see our FAQ below: http://secondlife.com/viewer-access-faq</string> + <string name="LoginFailed">Grid emergency login failure. +If you feel this is an error, please contact support@secondlife.com.</string> <string name="LoginIntermediateOptionalUpdateAvailable">Optional viewer update available: [VERSION]</string> <string name="LoginFailedRequiredUpdate">Required viewer update: [VERSION]</string> <string name="LoginFailedAlreadyLoggedIn">This agent is already logged in. @@ -152,15 +155,18 @@ People with free accounts will not be able to access Second Life during this tim <string name="LoginFailedComputerProhibited">Second Life cannot be accessed from this computer. If you feel this is an error, please contact support@secondlife.com.</string> + <!--'Pacific time' placeholder for [TIME] in case time from server can't be decoded--> + <string name="PacificTime">Pacific Time</string> <string name="LoginFailedAcountSuspended">Your account is not accessible until -[TIME] Pacific Time.</string> +[TIME]. +If you feel this is an error, please contact support@secondlife.com.</string> <string name="LoginFailedAccountDisabled">We are unable to complete your request at this time. Please contact Second Life support for assistance at http://support.secondlife.com.</string> <string name="LoginFailedTransformError">Data inconsistency found during login. Please contact support@secondlife.com.</string> <string name="LoginFailedAccountMaintenance">Your account is undergoing minor maintenance. Your account is not accessible until -[TIME] Pacific Time. +[TIME]. If you feel this is an error, please contact support@secondlife.com.</string> <string name="LoginFailedPendingLogoutFault">Request for logout responded with a fault from simulator.</string> <string name="LoginFailedPendingLogout">The system is logging you out right now. @@ -399,6 +405,7 @@ http://secondlife.com/support for help fixing this problem. <string name="symbolic link">link</string> <string name="symbolic folder link">folder link</string> <string name="settings blob">settings</string> + <string name="render material">material</string> <string name="mesh">mesh</string> <!-- llvoavatar. Displayed in the avatar chat bubble --> @@ -2414,6 +2421,7 @@ If you continue to receive this message, please contact Second Life support for <string name="Clothing" value=" Clothing," /> <string name="Gestures" value=" Gestures," /> <string name="Landmarks" value=" Landmarks," /> + <string name="Materials" value=" Materials," /> <string name="Notecards" value=" Notecards," /> <string name="Objects" value=" Objects," /> <string name="Scripts" value=" Scripts," /> @@ -3835,6 +3843,7 @@ Abuse Report</string> <string name="New Physics">New Physics</string> <string name="Invalid Wearable">Invalid Wearable</string> <string name="New Gesture">New Gesture</string> + <string name="New Material">New Material</string> <string name="New Script">New Script</string> <string name="New Note">New Note</string> <string name="New Folder">New Folder</string> @@ -4255,6 +4264,9 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string> <string name="ExperiencePermissionShort16">Sit</string> <string name="ExperiencePermissionShort17">Environment</string> + <!-- PBR Materials --> + <string name="Material Texture Name Header">Textures present this material: </string> + <!-- Conversation log messages --> <string name="logging_calls_disabled_log_empty"> Conversations are not being logged. To begin keeping a log, choose "Save: Log only" or "Save: Log and transcripts" under Preferences > Chat. diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index e5598978ce..4b7f6a0081 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -178,7 +178,7 @@ Versión del servidor de voz: [VOICE_VERSION] <string name="LoginFailedNoNetwork"> Error de red: no se ha podido conectar; por favor, revisa tu conexión a internet. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Error en el inicio de sesión. </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index f7545f08d2..16423503e7 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -187,7 +187,7 @@ Voice Server Version: [VOICE_VERSION] <string name="LoginFailedNoNetwork"> Erreur réseau : impossible d'établir la connexion. Veuillez vérifier votre connexion réseau. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Échec de la connexion. </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 7690e02692..ea972e5a13 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -183,7 +183,7 @@ Versione server voce: [VOICE_VERSION] <string name="LoginFailedNoNetwork"> Errore di rete: Non è stato possibile stabilire un collegamento, controlla la tua connessione. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Accesso non riuscito. </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index b4bc36a800..344f9fcd94 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -186,7 +186,7 @@ LOD 係数: [LOD_FACTOR] <string name="LoginFailedNoNetwork"> ネットワークエラー:接続を確立できませんでした。お使いのネットワーク接続をご確認ください。 </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> ログインに失敗しました。 </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml index cf033df3c9..2b182dc3cc 100644 --- a/indra/newview/skins/default/xui/pl/strings.xml +++ b/indra/newview/skins/default/xui/pl/strings.xml @@ -143,7 +143,7 @@ Wersja serwera głosu (Voice Server): [VOICE_VERSION] <string name="LoginFailedNoNetwork"> Błąd sieci: Brak połączenia z siecią, sprawdź status swojego połączenia internetowego. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Logowanie nie powiodło się. </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index c72a41fd3a..7c593ab3be 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -178,7 +178,7 @@ Versão do servidor de voz: [VOICE_VERSION] <string name="LoginFailedNoNetwork"> Erro de rede: Falha de conexão: verifique sua conexão à internet. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Falha do login. </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index ee2dcfe9cc..95b1664279 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -187,7 +187,7 @@ SLURL: <nolink>[SLURL]</nolink> <string name="LoginFailedNoNetwork"> Ошибка сети: не удалось установить соединение. Проверьте подключение к сети. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Ошибка входа. </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index 982de76a5b..74a6b3cac3 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -187,7 +187,7 @@ Ses Sunucusu Sürümü: [VOICE_VERSION] <string name="LoginFailedNoNetwork"> Ağ hatası: Bağlantı kurulamadı, lütfen ağ bağlantınızı kontrol edin. </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> Oturum açılamadı. </string> <string name="Quit"> diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml index 3221cde3b7..a8d5fd90bb 100644 --- a/indra/newview/skins/default/xui/zh/strings.xml +++ b/indra/newview/skins/default/xui/zh/strings.xml @@ -187,7 +187,7 @@ LibVLC版本:[LIBVLC_VERSION]N] <string name="LoginFailedNoNetwork"> 網路錯誤:無法建立連線,請檢查網路連線是否正常。 </string> - <string name="LoginFailed"> + <string name="LoginFailedHeader"> 登入失敗。 </string> <string name="Quit"> diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index a52c3dcef9..696fe3536c 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -223,6 +223,7 @@ bool llHashedUniqueID(unsigned char* id) #include "../llappviewer.h" void LLAppViewer::forceQuit(void) {} bool LLAppViewer::isUpdaterMissing() { return true; } +bool LLAppViewer::waitForUpdater() { return false; } LLAppViewer * LLAppViewer::sInstance = 0; //----------------------------------------------------------------------------- |