diff --git a/hdr_output/color_sweep/color_sweep.tscn b/hdr_output/color_sweep/color_sweep.tscn new file mode 100644 index 0000000000..d93877dffd --- /dev/null +++ b/hdr_output/color_sweep/color_sweep.tscn @@ -0,0 +1,97 @@ +[gd_scene format=3 uid="uid://drlb4o61s5wsk"] + +[ext_resource type="Script" uid="uid://cqjmg63jbxlns" path="res://color_sweep/colour_sweep.gd" id="1_3qbqk"] +[ext_resource type="Shader" uid="uid://upgu5h4jlibh" path="res://color_sweep/colour_sweep.gdshader" id="2_hfxc4"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_lquwl"] +shader = ExtResource("2_hfxc4") +shader_parameter/log2_min = -18.0 +shader_parameter/log2_max = 5.0 +shader_parameter/clip_to_max = false +shader_parameter/max_value = 10.0 + +[sub_resource type="QuadMesh" id="QuadMesh_7mycd"] + +[node name="ColorSweep" type="Control" unique_id=784950953] +layout_mode = 3 +anchors_preset = 0 +script = ExtResource("1_3qbqk") + +[node name="ColourSweepMesh" type="MeshInstance2D" parent="." unique_id=852978860] +unique_name_in_owner = true +material = SubResource("ShaderMaterial_lquwl") +position = Vector2(414.00003, 303) +scale = Vector2(822.00006, -528.00006) +mesh = SubResource("QuadMesh_7mycd") + +[node name="Tooltip" type="Control" parent="." unique_id=1015235051] +anchors_preset = 0 +offset_left = 3.0 +offset_top = 39.0 +offset_right = 825.0 +offset_bottom = 567.0 +tooltip_text = "The upper tick mark indicates +output_max_linear_value. + +The other tick marks are multiples +of 0.01, 0.1, 1.0, 10.0, etc. with +the rightmost white tick mark +indicating 0.1 and the leftmost +black tick mark indicating 0.2." + +[node name="HBoxContainer" type="HBoxContainer" parent="." unique_id=832456838] +layout_mode = 0 +offset_top = 2.0 +offset_right = 828.0 +offset_bottom = 42.0 +alignment = 1 + +[node name="Label" type="Label" parent="HBoxContainer" unique_id=873923751] +layout_mode = 2 +text = "Min" + +[node name="MinHSlider" type="HSlider" parent="HBoxContainer" unique_id=2106554318] +unique_name_in_owner = true +custom_minimum_size = Vector2(180, 0) +layout_mode = 2 +size_flags_vertical = 4 +min_value = -25.0 +max_value = 10.0 +step = 0.05000000000291038 +value = -13.999999999359712 + +[node name="Label2" type="Label" parent="HBoxContainer" unique_id=473575971] +layout_mode = 2 +text = "Max" + +[node name="MaxHSlider" type="HSlider" parent="HBoxContainer" unique_id=1145534836] +unique_name_in_owner = true +custom_minimum_size = Vector2(180, 0) +layout_mode = 2 +size_flags_vertical = 4 +min_value = -25.0 +max_value = 10.0 +step = 0.05000000000291038 +value = 5.0000000017462405 + +[node name="SweepMinLabel" type="Label" parent="." unique_id=648280970] +unique_name_in_owner = true +layout_mode = 0 +offset_left = 4.0 +offset_top = 10.0 +offset_right = 301.0 +offset_bottom = 33.0 +text = "0.000 (0.01 nits)" + +[node name="SweepMaxLabel" type="Label" parent="." unique_id=177120907] +unique_name_in_owner = true +layout_mode = 0 +offset_left = 499.0 +offset_top = 10.0 +offset_right = 823.0 +offset_bottom = 33.0 +text = "32.00 (13824.00 nits)" +horizontal_alignment = 2 + +[connection signal="value_changed" from="HBoxContainer/MinHSlider" to="." method="_on_min_h_slider_value_changed"] +[connection signal="value_changed" from="HBoxContainer/MaxHSlider" to="." method="_on_max_h_slider_value_changed"] diff --git a/hdr_output/color_sweep/colour_sweep.gd b/hdr_output/color_sweep/colour_sweep.gd new file mode 100644 index 0000000000..441f122eab --- /dev/null +++ b/hdr_output/color_sweep/colour_sweep.gd @@ -0,0 +1,24 @@ +extends Control + +var clip_to_max_lum: bool = false + + +func _process(_delta: float) -> void: + var window: Window = get_window() + var window_id = get_window().get_window_id() + var sm: ShaderMaterial = %ColourSweepMesh.material as ShaderMaterial + sm.set_shader_parameter("max_value", window.get_output_max_linear_value()); + %SweepMinLabel.text = "%0.3f (%0.2f nits)" % [pow(2, %MinHSlider.value), pow(2, %MinHSlider.value) * DisplayServer.window_get_hdr_output_current_reference_luminance(window_id)] + %SweepMaxLabel.text = "%0.2f (%0.2f nits)" % [pow(2, %MaxHSlider.value), pow(2, %MaxHSlider.value) * DisplayServer.window_get_hdr_output_current_reference_luminance(window_id)] + + +func _on_min_h_slider_value_changed(value: float) -> void: + %MaxHSlider.min_value = value; + var sm: ShaderMaterial = %ColourSweepMesh.material as ShaderMaterial + sm.set_shader_parameter("log2_min", value) + + +func _on_max_h_slider_value_changed(value: float) -> void: + %MinHSlider.max_value = value; + var sm: ShaderMaterial = %ColourSweepMesh.material as ShaderMaterial + sm.set_shader_parameter("log2_max", value) diff --git a/hdr_output/color_sweep/colour_sweep.gd.uid b/hdr_output/color_sweep/colour_sweep.gd.uid new file mode 100644 index 0000000000..44137e9aa9 --- /dev/null +++ b/hdr_output/color_sweep/colour_sweep.gd.uid @@ -0,0 +1 @@ +uid://cqjmg63jbxlns diff --git a/hdr_output/color_sweep/colour_sweep.gdshader b/hdr_output/color_sweep/colour_sweep.gdshader new file mode 100644 index 0000000000..08dec05913 --- /dev/null +++ b/hdr_output/color_sweep/colour_sweep.gdshader @@ -0,0 +1,106 @@ +shader_type canvas_item; +render_mode unshaded; + +uniform float log2_min = -18.0; +uniform float log2_max = 5.0; +uniform bool clip_to_max = false; +uniform float max_value = 10; + +void fragment() { + vec3 color; + float top_bar = 0.05; + float log2_value = UV.x * (log2_max - log2_min) + log2_min; + float scale = pow(2.0, log2_value); + + if (UV.y >= top_bar) + { + float padding = 0.005; + float y = (UV.y - top_bar - padding) / (1.0 - top_bar - padding * 2.0); + y = clamp(y, 0.0, 1.0); + float segments = 1.0 / 6.0; + vec3 col = vec3(0); + if (y < segments) + { + col.r = 1.0; + col.g = y / segments; + col.b = 0.0; + } + else if (y < segments * 2.0) + { + col.r = (y - segments * 2.0) / -segments; + col.g = 1.0; + col.b = 0.0; + } + else if (y < segments * 3.0) + { + col.r = 0.0; + col.g = 1.0; + col.b = (y - segments * 2.0) / segments; + } + else if (y < segments * 4.0) + { + col.r = 0.0; + col.g = (y - segments * 4.0) / -segments; + col.b = 1.0; + } + else if (y < segments * 5.0) + { + col.r = (y - segments * 4.0) / segments; + col.g = 0.0; + col.b = 1.0; + } + else + { + col.r = 1.0; + col.g = 0.0; + col.b = (y - segments * 6.0) / -segments; + } + + color = col * scale; + } + else + { + color = vec3(1.0) * scale; + + if (UV.y < 0.01) { + // Max value mark: + float max_log2 = log2(max_value); + float scale_log2 = log2(scale); + float mark_size = 0.03; + if (scale_log2 > max_log2 - mark_size && scale_log2 < max_log2 + mark_size) { + color = vec3(0); + } + } else if (UV.y > 0.03) { + // Log scale marks: + float tick_col = scale > 0.184 ? 0.0 : 1.0; + while (scale >= 1.0) { + scale /= 10.0; + } + while (scale < 0.1) { + scale *= 10.0; + } + float tick_threshold = scale * 0.02; + if ((scale > 1.0 - tick_threshold && scale < 1.0 + tick_threshold) + || (scale > 0.0 - tick_threshold && scale < 0.0 + tick_threshold) + || (scale > 0.1 - tick_threshold && scale < 0.1 + tick_threshold)) { + color = vec3(tick_col); + } else if (UV.y > 0.04 + && ((scale > 0.9 - tick_threshold && scale < 0.9 + tick_threshold) + || (scale > 0.8 - tick_threshold && scale < 0.8 + tick_threshold) + || (scale > 0.7 - tick_threshold && scale < 0.7 + tick_threshold) + || (scale > 0.6 - tick_threshold && scale < 0.6 + tick_threshold) + || (scale > 0.5 - tick_threshold && scale < 0.5 + tick_threshold) + || (scale > 0.4 - tick_threshold && scale < 0.4 + tick_threshold) + || (scale > 0.3 - tick_threshold && scale < 0.3 + tick_threshold) + || (scale > 0.2 - tick_threshold && scale < 0.2 + tick_threshold))) { + color = vec3(tick_col); + } + } + } + + if (clip_to_max) { + color = min(color, max_value); + } + + COLOR = vec4(color.rgb, 1.0); +} diff --git a/hdr_output/color_sweep/colour_sweep.gdshader.uid b/hdr_output/color_sweep/colour_sweep.gdshader.uid new file mode 100644 index 0000000000..6c38c4b85b --- /dev/null +++ b/hdr_output/color_sweep/colour_sweep.gdshader.uid @@ -0,0 +1 @@ +uid://upgu5h4jlibh diff --git a/hdr_output/environment/3d_environment.tscn b/hdr_output/environment/3d_environment.tscn new file mode 100644 index 0000000000..8040e666f2 --- /dev/null +++ b/hdr_output/environment/3d_environment.tscn @@ -0,0 +1,28 @@ +[gd_scene format=3 uid="uid://c0wukesav63su"] + +[ext_resource type="PackedScene" uid="uid://cyg6jtuudogcg" path="res://environment/gpu_particles_fire.tscn" id="1_oevuw"] + +[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_7l7or"] +sky_top_color = Color(0.34199998, 0.5161667, 0.76, 1) + +[sub_resource type="Sky" id="Sky_oevuw"] +sky_material = SubResource("ProceduralSkyMaterial_7l7or") + +[sub_resource type="Environment" id="Environment_dg77c"] +background_mode = 2 +sky = SubResource("Sky_oevuw") +tonemap_mode = 4 +tonemap_agx_contrast = 1.32 + +[node name="Node3D" type="Node3D" unique_id=229028905] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=522993847] +environment = SubResource("Environment_dg77c") + +[node name="Camera3D" type="Camera3D" parent="." unique_id=1229274230] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2.0156713) + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1268142717] + +[node name="GPUParticlesFire" parent="." unique_id=1592479161 instance=ExtResource("1_oevuw")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.7439877, 0) diff --git a/hdr_output/environment/fire.tscn b/hdr_output/environment/fire.tscn new file mode 100644 index 0000000000..14a1009664 --- /dev/null +++ b/hdr_output/environment/fire.tscn @@ -0,0 +1,44 @@ +[gd_scene format=3 uid="uid://bcif16iayg5dj"] + +[ext_resource type="Texture2D" uid="uid://dkl7yvfg3ivr3" path="res://fire_particle.png" id="1_2pqqt"] + +[sub_resource type="CanvasItemMaterial" id="1"] +blend_mode = 1 + +[sub_resource type="Curve" id="2"] +_limits = [-360.0, 360.0, 0.0, 1.0] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 85.0781), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="CurveTexture" id="3"] +curve = SubResource("2") + +[sub_resource type="Gradient" id="Gradient_wdtkk"] +offsets = PackedFloat32Array(0, 0.142857, 0.506494, 0.961039) +colors = PackedColorArray(0, 0, 0.803922, 1, 0.858824, 0.180392, 0.0470588, 1, 0.788235, 0.294118, 0, 1, 0, 0, 0, 0) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_fv41j"] +gradient = SubResource("Gradient_wdtkk") + +[sub_resource type="Curve" id="4"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.11, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 3 + +[sub_resource type="CurveTexture" id="5"] +curve = SubResource("4") + +[sub_resource type="ParticleProcessMaterial" id="6"] +emission_shape = 1 +emission_sphere_radius = 8.0 +angular_velocity_curve = SubResource("3") +gravity = Vector3(0, -250, 0) +scale_curve = SubResource("5") +color_ramp = SubResource("GradientTexture1D_fv41j") + +[node name="Fire" type="GPUParticles2D" unique_id=1051806849] +texture_filter = 4 +material = SubResource("1") +amount = 32 +texture = ExtResource("1_2pqqt") +preprocess = 1.0 +process_material = SubResource("6") diff --git a/hdr_output/environment/fire_particle.png b/hdr_output/environment/fire_particle.png new file mode 100644 index 0000000000..d0e4a98c21 Binary files /dev/null and b/hdr_output/environment/fire_particle.png differ diff --git a/hdr_output/environment/fire_particle.png.import b/hdr_output/environment/fire_particle.png.import new file mode 100644 index 0000000000..c763c3d257 --- /dev/null +++ b/hdr_output/environment/fire_particle.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dkl7yvfg3ivr3" +path="res://.godot/imported/fire_particle.png-2d5c46863bbeaf227772f709dff146aa.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://environment/fire_particle.png" +dest_files=["res://.godot/imported/fire_particle.png-2d5c46863bbeaf227772f709dff146aa.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/hdr_output/environment/gpu_particles_fire.tscn b/hdr_output/environment/gpu_particles_fire.tscn new file mode 100644 index 0000000000..4c21a01e18 --- /dev/null +++ b/hdr_output/environment/gpu_particles_fire.tscn @@ -0,0 +1,76 @@ +[gd_scene format=3 uid="uid://cyg6jtuudogcg"] + +[ext_resource type="Texture2D" uid="uid://6kc8qumfqvg3" path="res://kenney/smoke_05.png" id="1_bhdag"] + +[sub_resource type="Gradient" id="Gradient_827lf"] +interpolation_mode = 2 +offsets = PackedFloat32Array(0.01875, 0.0722892, 0.433735, 0.716867, 1) +colors = PackedColorArray(0, 0, 0, 1, 0.686275, 0.188235, 0, 1, 1, 0.517647, 0.0784314, 1, 1, 0.0784314, 0, 0.447059, 0.25098, 0.25098, 0.25098, 0) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_2374g"] +gradient = SubResource("Gradient_827lf") + +[sub_resource type="Curve" id="Curve_3eqrx"] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="CurveTexture" id="CurveTexture_3g7oh"] +curve = SubResource("Curve_3eqrx") + +[sub_resource type="ParticleProcessMaterial" id="ParticlesMaterial_wcmum"] +emission_shape = 3 +emission_box_extents = Vector3(0.5, 0, 0.5) +direction = Vector3(0, 1, 0) +spread = 3.5 +initial_velocity_min = 1.0 +initial_velocity_max = 4.0 +angular_velocity_max = 360.0 +gravity = Vector3(0, 0, 0) +damping_min = 2.0 +damping_max = 2.0 +scale_min = 0.1 +scale_max = 0.8 +scale_curve = SubResource("CurveTexture_3g7oh") +color = Color(4, 4, 4, 1) +color_ramp = SubResource("GradientTexture1D_2374g") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dod7h"] +transparency = 1 +shading_mode = 0 +vertex_color_use_as_albedo = true +albedo_texture = ExtResource("1_bhdag") +billboard_mode = 3 +particles_anim_h_frames = 1 +particles_anim_v_frames = 1 +particles_anim_loop = false +proximity_fade_enabled = true +proximity_fade_distance = 0.3 + +[sub_resource type="QuadMesh" id="QuadMesh_783ir"] +material = SubResource("StandardMaterial3D_dod7h") + +[node name="GPUParticlesFire" type="Node3D" unique_id=1592479161] + +[node name="GPUParticles3D" type="GPUParticles3D" parent="." unique_id=226837275] +amount = 125 +fixed_fps = 0 +interpolate = false +process_material = SubResource("ParticlesMaterial_wcmum") +draw_pass_1 = SubResource("QuadMesh_783ir") + +[node name="Decal" type="Decal" parent="." unique_id=705261104] +size = Vector3(2, 0.02, 2) +texture_albedo = ExtResource("1_bhdag") +modulate = Color(0, 0, 0, 1) + +[node name="Decal2" type="Decal" parent="." unique_id=1985595411] +transform = Transform3D(0.562646, 0, -0.826698, 0, 1, 0, 0.826698, 0, 0.562646, 0, 0, 0) +size = Vector3(3, 0.02, 2.2) +texture_albedo = ExtResource("1_bhdag") +modulate = Color(0, 0, 0, 1) + +[node name="Decal3" type="Decal" parent="." unique_id=41039049] +transform = Transform3D(-0.481494, 0, -0.87645, 0, 1, 0, 0.87645, 0, -0.481494, 0, 0, 0) +size = Vector3(3.2, 0.02, 2.6) +texture_albedo = ExtResource("1_bhdag") +modulate = Color(0, 0, 0, 1) diff --git a/hdr_output/environment/kenney/smoke_05.png b/hdr_output/environment/kenney/smoke_05.png new file mode 100644 index 0000000000..0ac46dcfea Binary files /dev/null and b/hdr_output/environment/kenney/smoke_05.png differ diff --git a/hdr_output/environment/kenney/smoke_05.png.import b/hdr_output/environment/kenney/smoke_05.png.import new file mode 100644 index 0000000000..7e6f60f74c --- /dev/null +++ b/hdr_output/environment/kenney/smoke_05.png.import @@ -0,0 +1,41 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6kc8qumfqvg3" +path.s3tc="res://.godot/imported/smoke_05.png-482cc5d4c97da667a5d6e91277a3e1b2.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://environment/kenney/smoke_05.png" +dest_files=["res://.godot/imported/smoke_05.png-482cc5d4c97da667a5d6e91277a3e1b2.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/hdr_output/environment/subviewport_scale.gd b/hdr_output/environment/subviewport_scale.gd new file mode 100644 index 0000000000..e9aade9a10 --- /dev/null +++ b/hdr_output/environment/subviewport_scale.gd @@ -0,0 +1,14 @@ +extends Node + +@onready var viewport: SubViewport = $SubViewport +@onready var viewport_initial_size: Vector2i = viewport.size +@onready var viewport_sprite: Sprite2D = $ViewportSprite + + +func _ready() -> void: + get_viewport().size_changed.connect(_root_viewport_size_changed) + + +func _root_viewport_size_changed() -> void: + viewport.size = Vector2.ONE * get_viewport().size.y + viewport_sprite.scale = Vector2.ONE * viewport_initial_size.y / get_viewport().size.y diff --git a/hdr_output/environment/subviewport_scale.gd.uid b/hdr_output/environment/subviewport_scale.gd.uid new file mode 100644 index 0000000000..eb33815c5b --- /dev/null +++ b/hdr_output/environment/subviewport_scale.gd.uid @@ -0,0 +1 @@ +uid://bb4pv67imdsne diff --git a/hdr_output/icon.svg b/hdr_output/icon.svg new file mode 100644 index 0000000000..c6bbb7d820 --- /dev/null +++ b/hdr_output/icon.svg @@ -0,0 +1 @@ + diff --git a/hdr_output/icon.svg.import b/hdr_output/icon.svg.import new file mode 100644 index 0000000000..49705982ad --- /dev/null +++ b/hdr_output/icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://de38mbn6q5ay6" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/hdr_output/in_game_hdr_settings/in_game_hdr_settings.gd b/hdr_output/in_game_hdr_settings/in_game_hdr_settings.gd new file mode 100644 index 0000000000..acb095fc6b --- /dev/null +++ b/hdr_output/in_game_hdr_settings/in_game_hdr_settings.gd @@ -0,0 +1,107 @@ +extends Control + +const HDR_SETTINGS_FILE = "user://hdr_settings.cfg" +const HDR_SETTINGS_SECTION = "HDR" + + +var _auto_adjust_reference: bool = false +var _auto_adjust_max: bool = false + + +func _on_visibility_changed() -> void: + if visible: + process_mode = Node.PROCESS_MODE_INHERIT + else: + process_mode = Node.PROCESS_MODE_DISABLED + + +func _ready() -> void: + var window: Window = get_window() + var window_id = get_window().get_window_id() + var hdr_settings: ConfigFile = ConfigFile.new() + if hdr_settings.load(HDR_SETTINGS_FILE) == OK: + window.hdr_output_requested = hdr_settings.get_value(HDR_SETTINGS_SECTION, "hdr_output_requested", window.hdr_output_requested) + DisplayServer.window_set_hdr_output_reference_luminance(hdr_settings.get_value(HDR_SETTINGS_SECTION, "hdr_output_reference_luminance", DisplayServer.window_get_hdr_output_reference_luminance(window_id)), window_id) + DisplayServer.window_set_hdr_output_max_luminance(hdr_settings.get_value(HDR_SETTINGS_SECTION, "hdr_output_max_luminance", DisplayServer.window_get_hdr_output_max_luminance(window_id)), window_id) + + _auto_adjust_reference = DisplayServer.window_get_hdr_output_reference_luminance(window_id) < 0 + _auto_adjust_max = DisplayServer.window_get_hdr_output_max_luminance(window_id) < 0 + + +func save_settings() -> void: + var window: Window = get_window() + var window_id = get_window().get_window_id() + var hdr_settings: ConfigFile = ConfigFile.new() + hdr_settings.set_value(HDR_SETTINGS_SECTION, "hdr_output_requested", window.hdr_output_requested) + if window.hdr_output_requested: + hdr_settings.set_value(HDR_SETTINGS_SECTION, "hdr_output_reference_luminance", DisplayServer.window_get_hdr_output_reference_luminance(window_id)) + hdr_settings.set_value(HDR_SETTINGS_SECTION, "hdr_output_max_luminance", DisplayServer.window_get_hdr_output_max_luminance(window_id)) + hdr_settings.save(HDR_SETTINGS_FILE) + + +func erase_settings() -> void: + var hdr_settings: ConfigFile = ConfigFile.new() + if hdr_settings.load(HDR_SETTINGS_FILE) == OK: + hdr_settings.erase_section(HDR_SETTINGS_SECTION) + hdr_settings.save(HDR_SETTINGS_FILE) + + +func _process(_delta: float) -> void: + var window: Window = get_window() + var window_id = get_window().get_window_id() + var hdr_supported := window.is_hdr_output_supported() + %HDRCheckButton.disabled = !hdr_supported + + var hdr_output_enabled: bool = DisplayServer.window_is_hdr_output_enabled(window_id) + if %HDRCheckButton.button_pressed != hdr_output_enabled: + %HDRCheckButton.button_pressed = hdr_output_enabled + %HDROptions.visible = hdr_output_enabled && hdr_supported + + %BrightnessSlider.max_value = DisplayServer.window_get_hdr_output_current_max_luminance() + %BrightnessSlider.value = DisplayServer.window_get_hdr_output_current_reference_luminance(window_id) + %BrightnessLabel.text = "%0.0f" % DisplayServer.window_get_hdr_output_current_reference_luminance(window_id) + + $%MaxLumSlider.min_value = DisplayServer.window_get_hdr_output_current_reference_luminance(window_id) + %MaxLumSlider.value = DisplayServer.window_get_hdr_output_current_max_luminance() + %MaxLumLabel.text = "%0.0f" % DisplayServer.window_get_hdr_output_current_max_luminance() + + %ResetBrightness.disabled = DisplayServer.window_get_hdr_output_reference_luminance(window_id) < 0 + %ResetMaxLum.disabled = DisplayServer.window_get_hdr_output_max_luminance(window_id) < 0 + + +func _on_hdr_check_button_toggled(toggled_on: bool) -> void: + # Request HDR output to the display. + if !%HDRCheckButton.disabled: + get_window().hdr_output_requested = toggled_on + + +func _on_brightness_slider_value_changed(value: float) -> void: + if !_auto_adjust_reference: + var window_id = get_window().get_window_id() + DisplayServer.window_set_hdr_output_reference_luminance(value, window_id) + + +func _on_max_lum_slider_value_changed(value: float) -> void: + if !_auto_adjust_max: + var window_id = get_window().get_window_id() + DisplayServer.window_set_hdr_output_max_luminance(value, window_id) + + +func _on_reset_brightness_pressed() -> void: + var window_id = get_window().get_window_id() + DisplayServer.window_set_hdr_output_reference_luminance(-1, window_id) + _auto_adjust_reference = true + + +func _on_reset_max_lum_pressed() -> void: + var window_id = get_window().get_window_id() + DisplayServer.window_set_hdr_output_max_luminance(-1, window_id) + _auto_adjust_max = true + + +func _on_brightness_slider_drag_started() -> void: + _auto_adjust_reference = false + + +func _on_max_lum_slider_drag_started() -> void: + _auto_adjust_max = false diff --git a/hdr_output/in_game_hdr_settings/in_game_hdr_settings.gd.uid b/hdr_output/in_game_hdr_settings/in_game_hdr_settings.gd.uid new file mode 100644 index 0000000000..6a6f6217f3 --- /dev/null +++ b/hdr_output/in_game_hdr_settings/in_game_hdr_settings.gd.uid @@ -0,0 +1 @@ +uid://dhrj6aw08a5o0 diff --git a/hdr_output/in_game_hdr_settings/in_game_hdr_settings.tscn b/hdr_output/in_game_hdr_settings/in_game_hdr_settings.tscn new file mode 100644 index 0000000000..c8a109f9c5 --- /dev/null +++ b/hdr_output/in_game_hdr_settings/in_game_hdr_settings.tscn @@ -0,0 +1,110 @@ +[gd_scene load_steps=2 format=3 uid="uid://jnc4cr2mhg00"] + +[ext_resource type="Script" uid="uid://dhrj6aw08a5o0" path="res://in_game_hdr_settings/in_game_hdr_settings.gd" id="1_4pceo"] + +[node name="InGameHDRSettings" type="VBoxContainer"] +offset_right = 377.0 +offset_bottom = 225.0 +script = ExtResource("1_4pceo") + +[node name="Label" type="Label" parent="."] +layout_mode = 2 +text = "Player-facing in-game settings:" + +[node name="HDRCheckButton" type="CheckButton" parent="."] +unique_name_in_owner = true +layout_mode = 2 +disabled = true +text = "HDR" + +[node name="HDROptions" type="HBoxContainer" parent="."] +unique_name_in_owner = true +layout_mode = 2 + +[node name="Spacer" type="Control" parent="HDROptions"] +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="HDROptions"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="HBoxContainer" type="HBoxContainer" parent="HDROptions/VBoxContainer"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="HDROptions/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Brightness" + +[node name="BrightnessLabel" type="Label" parent="HDROptions/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "200" +horizontal_alignment = 2 + +[node name="HBoxContainer3" type="HBoxContainer" parent="HDROptions/VBoxContainer"] +layout_mode = 2 + +[node name="BrightnessSlider" type="HSlider" parent="HDROptions/VBoxContainer/HBoxContainer3"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 1 +min_value = 10.0 +max_value = 1000.0 +step = 10.0 +value = 200.0 +rounded = true + +[node name="ResetBrightness" type="Button" parent="HDROptions/VBoxContainer/HBoxContainer3"] +unique_name_in_owner = true +layout_mode = 2 +text = "Reset" + +[node name="HBoxContainer2" type="HBoxContainer" parent="HDROptions/VBoxContainer"] +layout_mode = 2 + +[node name="Label2" type="Label" parent="HDROptions/VBoxContainer/HBoxContainer2"] +layout_mode = 2 +text = "Max luminance" + +[node name="MaxLumLabel" type="Label" parent="HDROptions/VBoxContainer/HBoxContainer2"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "1000" +horizontal_alignment = 2 + +[node name="HBoxContainer4" type="HBoxContainer" parent="HDROptions/VBoxContainer"] +layout_mode = 2 + +[node name="MaxLumSlider" type="HSlider" parent="HDROptions/VBoxContainer/HBoxContainer4"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 1 +min_value = 200.0 +max_value = 2000.0 +step = 10.0 +value = 1000.0 +rounded = true + +[node name="ResetMaxLum" type="Button" parent="HDROptions/VBoxContainer/HBoxContainer4"] +unique_name_in_owner = true +layout_mode = 2 +text = "Reset" + +[node name="Button" type="Button" parent="."] +layout_mode = 2 +text = "Save" + +[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"] +[connection signal="toggled" from="HDRCheckButton" to="." method="_on_hdr_check_button_toggled"] +[connection signal="drag_started" from="HDROptions/VBoxContainer/HBoxContainer3/BrightnessSlider" to="." method="_on_brightness_slider_drag_started"] +[connection signal="value_changed" from="HDROptions/VBoxContainer/HBoxContainer3/BrightnessSlider" to="." method="_on_brightness_slider_value_changed"] +[connection signal="pressed" from="HDROptions/VBoxContainer/HBoxContainer3/ResetBrightness" to="." method="_on_reset_brightness_pressed"] +[connection signal="drag_started" from="HDROptions/VBoxContainer/HBoxContainer4/MaxLumSlider" to="." method="_on_max_lum_slider_drag_started"] +[connection signal="value_changed" from="HDROptions/VBoxContainer/HBoxContainer4/MaxLumSlider" to="." method="_on_max_lum_slider_value_changed"] +[connection signal="pressed" from="HDROptions/VBoxContainer/HBoxContainer4/ResetMaxLum" to="." method="_on_reset_max_lum_pressed"] +[connection signal="pressed" from="Button" to="." method="save_settings"] diff --git a/hdr_output/main.tscn b/hdr_output/main.tscn new file mode 100644 index 0000000000..a8d3310ae8 --- /dev/null +++ b/hdr_output/main.tscn @@ -0,0 +1,541 @@ +[gd_scene format=3 uid="uid://cikrx8e0qde6d"] + +[ext_resource type="Script" uid="uid://c74bp7pq3jbkx" path="res://main/developer_settings.gd" id="2_7mycd"] +[ext_resource type="PackedScene" uid="uid://jnc4cr2mhg00" path="res://in_game_hdr_settings/in_game_hdr_settings.tscn" id="3_h2yge"] +[ext_resource type="Script" uid="uid://bclxdn8806hud" path="res://main/max_val_label.gd" id="5_dg77c"] +[ext_resource type="PackedScene" uid="uid://drlb4o61s5wsk" path="res://color_sweep/color_sweep.tscn" id="6_7mycd"] +[ext_resource type="Script" uid="uid://fhoiawdcyegx" path="res://main/demo_scenes.gd" id="6_272bh"] +[ext_resource type="Texture2D" uid="uid://b335ssbw6ynt6" path="res://output_max_linear_value/Super Mountain Dusk/mountain.png" id="7_5vw27"] +[ext_resource type="Script" uid="uid://cpqmte6usoyyg" path="res://main/debug_info.gd" id="8_5vw27"] +[ext_resource type="Texture2D" uid="uid://cvecqn4m52x7x" path="res://output_max_linear_value/spark_particle2.png" id="8_kek77"] +[ext_resource type="Script" uid="uid://ow74i072fx6r" path="res://max_self_modulate.gd" id="9_4c57u"] +[ext_resource type="Script" uid="uid://bb4pv67imdsne" path="res://environment/subviewport_scale.gd" id="10_dg77c"] +[ext_resource type="PackedScene" uid="uid://c0wukesav63su" path="res://environment/3d_environment.tscn" id="11_dg77c"] +[ext_resource type="Script" uid="uid://b6cwewu4wkvv5" path="res://setup_instructions/setup_instructions.gd" id="13_w48qg"] +[ext_resource type="Script" uid="uid://dxtpfowo3fjm4" path="res://max_colour.gd" id="13_ycdy4"] + +[sub_resource type="Gradient" id="Gradient_4c57u"] +offsets = PackedFloat32Array(0, 0.0769231, 0.16568, 0.266272, 0.378698, 0.491124, 0.609467, 0.704142, 0.804734, 0.911243, 1) +colors = PackedColorArray(1, 1, 1, 1, 1, 0.152961, 0, 1, 1, 0.726562, 0, 1, 0.78125, 1, 0, 1, 0.289062, 1, 0, 1, 0, 1, 0.472656, 1, 0, 1, 0.835938, 1, 0, 0.71875, 1, 1, 0.21875, 0, 1, 1, 1, 0, 0.773438, 1, 1, 1, 1, 1) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_efxa6"] +gradient = SubResource("Gradient_4c57u") + +[sub_resource type="Curve" id="Curve_4c57u"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.24940729, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 3 + +[sub_resource type="CurveTexture" id="CurveTexture_efxa6"] +curve = SubResource("Curve_4c57u") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_dg77c"] +particle_flag_disable_z = true +radial_velocity_min = -2.2351742e-05 +radial_velocity_max = 166.64998 +gravity = Vector3(0, 0, 0) +linear_accel_min = 23.879997 +linear_accel_max = 83.59 +scale_curve = SubResource("CurveTexture_efxa6") +color_ramp = SubResource("GradientTexture1D_efxa6") + +[sub_resource type="ViewportTexture" id="ViewportTexture_efxa6"] +viewport_path = NodePath("DemoScenes/EnvironmentScene/SubViewport") + +[sub_resource type="SystemFont" id="SystemFont_7mycd"] +font_names = PackedStringArray("Monospace") +subpixel_positioning = 0 + +[node name="Control" type="Control" unique_id=1546781181] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=2107551733] +layout_mode = 0 +offset_right = 320.0 +offset_bottom = 648.0 + +[node name="ColorRect" type="ColorRect" parent="VBoxContainer" unique_id=467859451] +layout_mode = 2 +size_flags_vertical = 3 +color = Color(0.21710123, 0.21710123, 0.21710123, 1) + +[node name="InGameHDRSettings" parent="VBoxContainer/ColorRect" unique_id=1002679391 instance=ExtResource("3_h2yge")] +layout_mode = 0 +offset_left = 5.0 +offset_top = 7.0 +offset_right = 315.0 +offset_bottom = 233.0 + +[node name="ColorRect2" type="ColorRect" parent="VBoxContainer" unique_id=1685998796] +custom_minimum_size = Vector2(0, 398) +layout_mode = 2 +color = Color(0.21568628, 0.21568628, 0.21568628, 1) + +[node name="DeveloperSettings" type="VBoxContainer" parent="VBoxContainer/ColorRect2" unique_id=763217887] +layout_mode = 0 +offset_left = 5.0 +offset_top = 8.0 +offset_right = 315.0 +offset_bottom = 374.0 +script = ExtResource("2_7mycd") + +[node name="Label" type="Label" parent="VBoxContainer/ColorRect2/DeveloperSettings" unique_id=2123018716] +layout_mode = 2 +text = "Developer settings:" + +[node name="Button" type="Button" parent="VBoxContainer/ColorRect2/DeveloperSettings" unique_id=1727096126] +layout_mode = 2 +text = "Erase player settings" + +[node name="Label3" type="Label" parent="VBoxContainer/ColorRect2/DeveloperSettings" unique_id=182639080] +layout_mode = 2 +text = "Reference monitor calibration:" + +[node name="Control" type="Control" parent="VBoxContainer/ColorRect2/DeveloperSettings" unique_id=1779327274] +custom_minimum_size = Vector2(0, 78) +layout_mode = 2 + +[node name="MaxLumAdjustBacking" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=1341568457] +unique_name_in_owner = true +layout_mode = 0 +offset_left = 9.0 +offset_top = 4.0 +offset_right = 129.0 +offset_bottom = 74.0 + +[node name="MaxLumAdjustBelow2" type="Polygon2D" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=144371379] +unique_name_in_owner = true +self_modulate = Color(0.8848981, 0.8848981, 0.8848981, 1) +position = Vector2(40, 39) +scale = Vector2(50, 50) +polygon = PackedVector2Array(0, -0.5, 0.5, 0.5, -0.5, 0.5) + +[node name="MaxLumAdjustBelow3" type="Polygon2D" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=106732800] +unique_name_in_owner = true +self_modulate = Color(0.9407874, 0.9407874, 0.9407874, 1) +position = Vector2(98, 39) +scale = Vector2(50, 50) +polygon = PackedVector2Array(0, -0.5, 0.5, 0.5, -0.5, 0.5) + +[node name="ColorRect" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=443567928] +layout_mode = 0 +offset_left = 136.0 +offset_top = 4.0 +offset_right = 186.0 +offset_bottom = 39.0 +color = Color(1, 0, 0, 1) + +[node name="ColorRect2" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=1765336189] +layout_mode = 0 +offset_left = 193.0 +offset_top = 4.0 +offset_right = 243.0 +offset_bottom = 39.0 +pivot_offset = Vector2(44, 29) +color = Color(0, 1, 0, 1) + +[node name="ColorRect3" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=1445682559] +layout_mode = 0 +offset_left = 250.0 +offset_top = 4.0 +offset_right = 300.0 +offset_bottom = 39.0 +pivot_offset = Vector2(44, -4) +color = Color(0, 0, 1, 1) + +[node name="ColorRect4" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=1104706596] +layout_mode = 0 +offset_left = 136.0 +offset_top = 39.0 +offset_right = 186.0 +offset_bottom = 74.0 +color = Color(1, 0, 0, 1) +script = ExtResource("13_ycdy4") +sdr_colour = Color(1, 0, 0, 1) + +[node name="ColorRect5" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=2138302032] +layout_mode = 0 +offset_left = 193.0 +offset_top = 39.0 +offset_right = 243.0 +offset_bottom = 74.0 +pivot_offset = Vector2(0, 29) +color = Color(0, 1, 0, 1) +script = ExtResource("13_ycdy4") +sdr_colour = Color(0, 1, 0, 1) + +[node name="ColorRect6" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control" unique_id=1549780699] +layout_mode = 0 +offset_left = 250.0 +offset_top = 39.0 +offset_right = 300.0 +offset_bottom = 74.0 +pivot_offset = Vector2(0, -4) +color = Color(0, 0, 1, 1) +script = ExtResource("13_ycdy4") +sdr_colour = Color(0, 0, 1, 1) + +[node name="Label2" type="Label" parent="VBoxContainer/ColorRect2/DeveloperSettings" unique_id=332601797] +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 +size_flags_vertical = 6 +text = "Set max luminance as high as possible while maintaining the visibility of both triangles and the hue and saturation of the three colors. Tap Reset to use the value reported by the display. Example:" +autowrap_mode = 3 + +[node name="Control2" type="Control" parent="VBoxContainer/ColorRect2/DeveloperSettings" unique_id=1021742490] +custom_minimum_size = Vector2(0, 78) +layout_mode = 2 + +[node name="MaxLumAdjustBacking" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=1125706939] +layout_mode = 0 +offset_left = 9.0 +offset_top = 4.0 +offset_right = 129.0 +offset_bottom = 74.0 + +[node name="ExampleMaxLumAdjustBelow" type="Polygon2D" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=1291892689] +unique_name_in_owner = true +self_modulate = Color(0.8848981, 0.8848981, 0.8848981, 1) +position = Vector2(40, 39) +scale = Vector2(50, 50) +polygon = PackedVector2Array(0, -0.5, 0.5, 0.5, -0.5, 0.5) + +[node name="ExampleMaxLumAdjustBelow2" type="Polygon2D" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=1861809390] +unique_name_in_owner = true +self_modulate = Color(0.9407874, 0.9407874, 0.9407874, 1) +position = Vector2(98, 38.99997) +scale = Vector2(50, 50) +polygon = PackedVector2Array(0, -0.5, 0.5, 0.5, -0.5, 0.5) + +[node name="ColorRect7" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=137267310] +layout_mode = 0 +offset_left = 136.0 +offset_top = 4.0 +offset_right = 186.0 +offset_bottom = 39.0 +color = Color(0.735357, 0, 0, 1) + +[node name="ColorRect8" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=752449690] +layout_mode = 0 +offset_left = 193.0 +offset_top = 4.0 +offset_right = 243.0 +offset_bottom = 39.0 +pivot_offset = Vector2(44, 29) +color = Color(0, 0.735357, 0, 1) + +[node name="ColorRect9" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=167545516] +layout_mode = 0 +offset_left = 250.0 +offset_top = 4.0 +offset_right = 300.0 +offset_bottom = 39.0 +pivot_offset = Vector2(44, -4) +color = Color(0, 0, 0.735357, 1) + +[node name="ColorRect10" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=1401542410] +layout_mode = 0 +offset_left = 136.0 +offset_top = 39.0 +offset_right = 186.0 +offset_bottom = 74.0 +color = Color(1, 0, 0, 1) + +[node name="ColorRect11" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=534544741] +layout_mode = 0 +offset_left = 193.0 +offset_top = 39.0 +offset_right = 243.0 +offset_bottom = 74.0 +pivot_offset = Vector2(44, 29) +color = Color(0, 1, 0, 1) + +[node name="ColorRect12" type="ColorRect" parent="VBoxContainer/ColorRect2/DeveloperSettings/Control2" unique_id=793779675] +layout_mode = 0 +offset_left = 250.0 +offset_top = 39.0 +offset_right = 300.0 +offset_bottom = 74.0 +pivot_offset = Vector2(44, -4) +color = Color(0, 0, 1, 1) + +[node name="DebugInfo" type="Label" parent="." unique_id=480223336] +layout_mode = 0 +offset_left = 327.0 +offset_right = 624.0 +offset_bottom = 75.0 +mouse_filter = 0 +text = "Display Server supports HDR: true +Rendering Device supports HDR: true +Window supports HDR: true" +script = ExtResource("8_5vw27") + +[node name="BlackWhiteMax" type="Control" parent="." unique_id=1868827823] +custom_minimum_size = Vector2(97.615, 0) +anchors_preset = 0 +offset_left = 633.0 +offset_top = 2.0 +offset_right = 893.0 +offset_bottom = 77.0 + +[node name="Label" type="Label" parent="BlackWhiteMax" unique_id=1432220451] +layout_mode = 0 +offset_left = 9.0 +offset_top = 2.0 +offset_right = 89.0 +offset_bottom = 25.0 +text = "Black" +horizontal_alignment = 1 + +[node name="Black" type="ColorRect" parent="BlackWhiteMax" unique_id=255226634] +layout_mode = 0 +offset_left = 9.0 +offset_top = 25.0 +offset_right = 89.0 +offset_bottom = 45.0 +color = Color(0, 0, 0, 1) + +[node name="Label4" type="Label" parent="BlackWhiteMax" unique_id=10137459] +layout_mode = 0 +offset_left = 9.0 +offset_top = 46.0 +offset_right = 89.0 +offset_bottom = 69.0 +text = "0.00" +horizontal_alignment = 1 + +[node name="Label2" type="Label" parent="BlackWhiteMax" unique_id=733073890] +layout_mode = 0 +offset_left = 89.0 +offset_top = 2.0 +offset_right = 169.0 +offset_bottom = 25.0 +text = "White" +horizontal_alignment = 1 + +[node name="White" type="ColorRect" parent="BlackWhiteMax" unique_id=725348665] +layout_mode = 0 +offset_left = 89.0 +offset_top = 25.0 +offset_right = 169.0 +offset_bottom = 45.0 + +[node name="Label5" type="Label" parent="BlackWhiteMax" unique_id=1454876637] +layout_mode = 0 +offset_left = 89.0 +offset_top = 46.0 +offset_right = 169.0 +offset_bottom = 69.0 +text = "1.00" +horizontal_alignment = 1 + +[node name="Label3" type="Label" parent="BlackWhiteMax" unique_id=907524270] +layout_mode = 0 +offset_left = 169.0 +offset_top = 2.0 +offset_right = 249.0 +offset_bottom = 25.0 +text = "Max" +horizontal_alignment = 1 + +[node name="Max" type="ColorRect" parent="BlackWhiteMax" unique_id=1672818577] +layout_mode = 0 +offset_left = 169.0 +offset_top = 25.0 +offset_right = 249.0 +offset_bottom = 45.0 +script = ExtResource("13_ycdy4") + +[node name="Label6" type="Label" parent="BlackWhiteMax" unique_id=1095042380] +layout_mode = 0 +offset_left = 169.0 +offset_top = 46.0 +offset_right = 249.0 +offset_bottom = 69.0 +text = "1.00" +horizontal_alignment = 1 +script = ExtResource("5_dg77c") + +[node name="DemoScenes" type="ColorRect" parent="." unique_id=1892849244 node_paths=PackedStringArray("scenes")] +layout_mode = 0 +offset_left = 324.0 +offset_top = 78.0 +offset_right = 1152.0 +offset_bottom = 648.0 +color = Color(0.21568628, 0.21568628, 0.21568628, 1) +script = ExtResource("6_272bh") +scenes = [NodePath("output_max_linear_value"), NodePath("EnvironmentScene"), NodePath("ColorSweep"), NodePath("SetupInstructions")] + +[node name="Tab" type="ColorRect" parent="DemoScenes" unique_id=261230258] +layout_mode = 0 +offset_left = 586.0 +offset_top = -61.0 +offset_right = 828.0 +color = Color(0.21568628, 0.21568628, 0.21568628, 1) + +[node name="OptionButton" type="OptionButton" parent="DemoScenes/Tab" unique_id=1332299268] +layout_mode = 0 +offset_left = 9.0 +offset_top = 28.0 +offset_right = 234.0 +offset_bottom = 59.0 +selected = 0 +item_count = 4 +popup/item_0/text = "output_max_linear_value" +popup/item_0/id = 0 +popup/item_1/text = "Environment" +popup/item_1/id = 1 +popup/item_2/text = "Color sweep" +popup/item_2/id = 2 +popup/item_3/text = "Setup instructions" +popup/item_3/id = 3 + +[node name="Label" type="Label" parent="DemoScenes/Tab" unique_id=1342427115] +layout_mode = 0 +offset_left = 12.0 +offset_top = 3.0 +offset_right = 111.0 +offset_bottom = 26.0 +text = "Demo scene:" + +[node name="output_max_linear_value" type="Control" parent="DemoScenes" unique_id=1640634166] +anchors_preset = 0 +offset_right = 828.0 +offset_bottom = 570.0 + +[node name="Mountain" type="Node2D" parent="DemoScenes/output_max_linear_value" unique_id=1183547058] +position = Vector2(29, 27) + +[node name="Sun" type="ColorRect" parent="DemoScenes/output_max_linear_value/Mountain" unique_id=347517105] +offset_left = 73.0 +offset_top = 8.0 +offset_right = 239.0 +offset_bottom = 108.0 +color = Color(0.99215686, 0.7058824, 0.41568628, 1) +script = ExtResource("13_ycdy4") +sdr_colour = Color(0.99215686, 0.7058824, 0.41568628, 1) +max_linear_value_limit = 10.0 + +[node name="Mountain" type="Sprite2D" parent="DemoScenes/output_max_linear_value/Mountain" unique_id=1827667879] +texture_filter = 1 +texture_repeat = 1 +position = Vector2(160, 120) +texture = ExtResource("7_5vw27") + +[node name="Sparkles" type="GPUParticles2D" parent="DemoScenes/output_max_linear_value" unique_id=817018124] +texture_filter = 1 +position = Vector2(534, 165) +amount = 42 +texture = ExtResource("8_kek77") +process_material = SubResource("ParticleProcessMaterial_dg77c") +script = ExtResource("9_4c57u") + +[node name="Label" type="Label" parent="DemoScenes/output_max_linear_value" unique_id=558150534] +layout_mode = 0 +offset_left = 95.0 +offset_top = 458.0 +offset_right = 703.0 +offset_bottom = 533.0 +text = "DRAFT DEMO PROJECT +HELP WANTED +Please let @allenwp know if you have a high quality demo for use in this scene." +horizontal_alignment = 1 + +[node name="Label2" type="Label" parent="DemoScenes/output_max_linear_value" unique_id=2086992899] +layout_mode = 0 +offset_left = 315.0 +offset_top = 360.0 +offset_right = 519.0 +offset_bottom = 409.0 +text = "TODO: 3D model that uses +output_max_linear_value" + +[node name="EnvironmentScene" type="Control" parent="DemoScenes" unique_id=1160571939] +visible = false +anchors_preset = 0 +offset_left = 99.0 +offset_top = 390.0 +offset_right = 139.0 +offset_bottom = 430.0 +script = ExtResource("10_dg77c") + +[node name="SubViewport" type="SubViewport" parent="DemoScenes/EnvironmentScene" unique_id=628806123] +own_world_3d = true +handle_input_locally = false +msaa_3d = 2 +use_hdr_2d = true +size = Vector2i(570, 570) +render_target_update_mode = 4 + +[node name="Node3D" parent="DemoScenes/EnvironmentScene/SubViewport" unique_id=229028905 instance=ExtResource("11_dg77c")] + +[node name="ViewportSprite" type="Sprite2D" parent="DemoScenes/EnvironmentScene" unique_id=448833630] +position = Vector2(315, -105) +texture = SubResource("ViewportTexture_efxa6") + +[node name="Label2" type="Label" parent="DemoScenes/EnvironmentScene" unique_id=476553587] +layout_mode = 0 +offset_left = 8.0 +offset_top = 96.0 +offset_right = 616.0 +offset_bottom = 171.0 +text = "DRAFT DEMO PROJECT +HELP WANTED +Please let @allenwp know if you have a high quality demo for use in this scene." +horizontal_alignment = 1 + +[node name="Label" type="Label" parent="DemoScenes/EnvironmentScene" unique_id=524097135] +layout_mode = 0 +offset_left = -88.0 +offset_top = -374.0 +offset_right = 107.0 +offset_bottom = -325.0 +text = "TODO: 2D thing that uses +overbright colours" + +[node name="ColorSweep" parent="DemoScenes" unique_id=784950953 instance=ExtResource("6_7mycd")] +visible = false +layout_mode = 0 + +[node name="SetupInstructions" type="RichTextLabel" parent="DemoScenes" unique_id=660978631] +visible = false +layout_mode = 0 +offset_left = 55.0 +offset_top = 5.0 +offset_right = 776.0 +offset_bottom = 551.0 +focus_mode = 2 +theme_override_fonts/mono_font = SubResource("SystemFont_7mycd") +bbcode_enabled = true +text = "[font_size=20]Steps to enable HDR output in your project:[/font_size] + +1) Ensure all Environment resources do [i]not[/i] use SDR-only features: + - Tonemap Mode: Filmic or ACES + - Glow Blend Mode: Soft Light + - Adjustments: Color Correction + +2) Configure the [code]rendering/rendering_device/driver[/code] project setting to the following: + - macos: metal + - ios: metal + - windows: d3d12 + +3) Turn on the [code]rendering/viewport/hdr_2d[/code] project setting and also turn on [code]use_hdr_2d[/code] of all Subviewport and Windows that should support HDR output. + +4) Turn on the [code]display/window/hdr/request_hdr_output[/code] project setting and also turn on [code]hdr_output_requested[/code] of all other Windows that should support HDR output. + +5) [Optional] Provide in-game settings for the player to adjust HDR brightness and maximum luminance by copying [code]in_game_hdr_settings[/code] from this demo into your project. + +View the [url=\"https://github.com/godotengine/godot-docs/pull/11548\"]manual page[/url] to learn more about HDR output." +context_menu_enabled = true +vertical_alignment = 1 +selection_enabled = true +drag_and_drop_selection_enabled = false +script = ExtResource("13_w48qg") + +[connection signal="pressed" from="VBoxContainer/ColorRect2/DeveloperSettings/Button" to="VBoxContainer/ColorRect/InGameHDRSettings" method="erase_settings"] +[connection signal="item_selected" from="DemoScenes/Tab/OptionButton" to="DemoScenes" method="_on_demo_scene_item_selected"] +[connection signal="meta_clicked" from="DemoScenes/SetupInstructions" to="DemoScenes/SetupInstructions" method="_on_meta_clicked"] diff --git a/hdr_output/main/debug_info.gd b/hdr_output/main/debug_info.gd new file mode 100644 index 0000000000..bdc0f9db17 --- /dev/null +++ b/hdr_output/main/debug_info.gd @@ -0,0 +1,23 @@ +extends Label + +func _process(_delta: float) -> void: + var window := get_window() + + var device := RenderingServer.get_rendering_device(); + + var device_has_hdr: bool = false + if device: + device_has_hdr = device.has_feature(RenderingDevice.SUPPORTS_HDR_OUTPUT) + + text = "" + text += "Display Server supports HDR: %s\n" % DisplayServer.has_feature(DisplayServer.FEATURE_HDR_OUTPUT) + text += "Rendering Device supports HDR: %s\n" % device_has_hdr + text += "Window supports HDR: %s\n" % DisplayServer.window_is_hdr_output_supported(window.get_window_id()) + + if !DisplayServer.has_feature(DisplayServer.FEATURE_HDR_OUTPUT): + tooltip_text = "Display Server does not support\nHDR output. This usually means\nthat Godot does not support HDR\noutput on your current platform,\nbut other Display Server drivers may support HDR output.\n\n" + elif !device_has_hdr: + tooltip_text = "Rendering Device does not support\nHDR output. Try changing the\nRendering Device driver in your\nproject settings to a driver that supports\nHDR output, such as d3d12 for Windows\nand metal for Mac OS.\n\n" + elif !DisplayServer.window_is_hdr_output_supported(window.get_window_id()): + tooltip_text = "Window does not support HDR output.\nPlease ensure that your window is\npositioned on a screen that is currently\nin HDR mode." + diff --git a/hdr_output/main/debug_info.gd.uid b/hdr_output/main/debug_info.gd.uid new file mode 100644 index 0000000000..6d41227490 --- /dev/null +++ b/hdr_output/main/debug_info.gd.uid @@ -0,0 +1 @@ +uid://cpqmte6usoyyg diff --git a/hdr_output/main/demo_scenes.gd b/hdr_output/main/demo_scenes.gd new file mode 100644 index 0000000000..5b84db3aee --- /dev/null +++ b/hdr_output/main/demo_scenes.gd @@ -0,0 +1,12 @@ +extends Node + +@export var scenes: Array[Control] + + +func _ready() -> void: + _on_demo_scene_item_selected(0) + + +func _on_demo_scene_item_selected(index: int) -> void: + for i in range(scenes.size()): + scenes[i].visible = i == index diff --git a/hdr_output/main/demo_scenes.gd.uid b/hdr_output/main/demo_scenes.gd.uid new file mode 100644 index 0000000000..c76ef4bd8c --- /dev/null +++ b/hdr_output/main/demo_scenes.gd.uid @@ -0,0 +1 @@ +uid://fhoiawdcyegx diff --git a/hdr_output/main/developer_settings.gd b/hdr_output/main/developer_settings.gd new file mode 100644 index 0000000000..74fe4c7357 --- /dev/null +++ b/hdr_output/main/developer_settings.gd @@ -0,0 +1,24 @@ +extends VBoxContainer + +func _process(_delta: float) -> void: + var window: Window = get_window() + var adjustment_step_1 = 0.2 + var adjustment_step_2 = 0.4 + + var max_val: float = window.get_output_max_linear_value() + + %MaxLumAdjustBacking.color = Color(max_val, max_val, max_val).linear_to_srgb() + + var max_adjust_material_value = pow(2.0, (log(max_val) / log(2.0)) - adjustment_step_2) + %MaxLumAdjustBelow2.self_modulate = Color(max_adjust_material_value, max_adjust_material_value, max_adjust_material_value).linear_to_srgb() + + max_adjust_material_value = pow(2.0, (log(max_val) / log(2.0)) - adjustment_step_1) + %MaxLumAdjustBelow3.self_modulate = Color(max_adjust_material_value, max_adjust_material_value, max_adjust_material_value).linear_to_srgb() + + #Examples: + + max_adjust_material_value = pow(2.0, (log(1.0) / log(2.0)) - adjustment_step_2) + %ExampleMaxLumAdjustBelow.self_modulate = Color(max_adjust_material_value, max_adjust_material_value, max_adjust_material_value).linear_to_srgb() + + max_adjust_material_value = pow(2.0, (log(1.0) / log(2.0)) - adjustment_step_1) + %ExampleMaxLumAdjustBelow2.self_modulate = Color(max_adjust_material_value, max_adjust_material_value, max_adjust_material_value).linear_to_srgb() diff --git a/hdr_output/main/developer_settings.gd.uid b/hdr_output/main/developer_settings.gd.uid new file mode 100644 index 0000000000..878db0449e --- /dev/null +++ b/hdr_output/main/developer_settings.gd.uid @@ -0,0 +1 @@ +uid://c74bp7pq3jbkx diff --git a/hdr_output/main/max_val_label.gd b/hdr_output/main/max_val_label.gd new file mode 100644 index 0000000000..800a4b4f84 --- /dev/null +++ b/hdr_output/main/max_val_label.gd @@ -0,0 +1,5 @@ +extends Label + + +func _process(_delta: float) -> void: + text = "%0.2f" % get_window().get_output_max_linear_value() diff --git a/hdr_output/main/max_val_label.gd.uid b/hdr_output/main/max_val_label.gd.uid new file mode 100644 index 0000000000..6c919aefef --- /dev/null +++ b/hdr_output/main/max_val_label.gd.uid @@ -0,0 +1 @@ +uid://bclxdn8806hud diff --git a/hdr_output/max_colour.gd b/hdr_output/max_colour.gd new file mode 100644 index 0000000000..6951744e88 --- /dev/null +++ b/hdr_output/max_colour.gd @@ -0,0 +1,26 @@ +extends Node + +@export var sdr_colour: Color = Color.WHITE +@export_range(0, 20, 0.1, "or_less", "or_greater") var max_linear_value_limit: float = -1.0 + + +func _process(_delta: float) -> void: + # Adjust the brightness of color to be the brightest possible, regardless + # of SDR or HDR output, but no brighter than max_linear_value_limit. + var max_linear_value = get_window().get_output_max_linear_value() + if max_linear_value_limit >= 0.0: + max_linear_value = minf(max_linear_value, max_linear_value_limit) + self.color = normalize_color(sdr_colour, max_linear_value) + + +func normalize_color(srgb_color, max_linear_value = 1.0): + # Color must be linear-encoded to use math operations. + var linear_color = srgb_color.srgb_to_linear() + var max_rgb_value = maxf(linear_color.r, maxf(linear_color.g, linear_color.b)) + var brightness_scale = max_linear_value / max_rgb_value + linear_color *= brightness_scale + # Undo changes to the alpha channel, which should not be modified. + linear_color.a = srgb_color.a + # Convert back to nonlinear sRGB encoding, which is required for Color in + # Godot unless stated otherwise. + return linear_color.linear_to_srgb() diff --git a/hdr_output/max_colour.gd.uid b/hdr_output/max_colour.gd.uid new file mode 100644 index 0000000000..ed57d295c1 --- /dev/null +++ b/hdr_output/max_colour.gd.uid @@ -0,0 +1 @@ +uid://dxtpfowo3fjm4 diff --git a/hdr_output/max_self_modulate.gd b/hdr_output/max_self_modulate.gd new file mode 100644 index 0000000000..b1845ed4d3 --- /dev/null +++ b/hdr_output/max_self_modulate.gd @@ -0,0 +1,26 @@ +extends CanvasItem + +@export var sdr_self_modulate: Color = Color.WHITE +@export_range(0, 20, 0.1, "or_less", "or_greater") var max_linear_value_limit: float = -1.0 + + +func _process(_delta: float) -> void: + # Adjust the brightness of color to be the brightest possible, regardless + # of SDR or HDR output, but no brighter than max_linear_value_limit. + var max_linear_value = get_window().get_output_max_linear_value() + if max_linear_value_limit >= 0.0: + max_linear_value = minf(max_linear_value, max_linear_value_limit) + self.self_modulate = normalize_color(sdr_self_modulate, max_linear_value) + + +func normalize_color(srgb_color, max_linear_value = 1.0): + # Color must be linear-encoded to use math operations. + var linear_color = srgb_color.srgb_to_linear() + var max_rgb_value = maxf(linear_color.r, maxf(linear_color.g, linear_color.b)) + var brightness_scale = max_linear_value / max_rgb_value + linear_color *= brightness_scale + # Undo changes to the alpha channel, which should not be modified. + linear_color.a = srgb_color.a + # Convert back to nonlinear sRGB encoding, which is required for Color in + # Godot unless stated otherwise. + return linear_color.linear_to_srgb() diff --git a/hdr_output/max_self_modulate.gd.uid b/hdr_output/max_self_modulate.gd.uid new file mode 100644 index 0000000000..f08f7417b1 --- /dev/null +++ b/hdr_output/max_self_modulate.gd.uid @@ -0,0 +1 @@ +uid://ow74i072fx6r diff --git a/hdr_output/output_max_linear_value/Super Mountain Dusk/mountain.png b/hdr_output/output_max_linear_value/Super Mountain Dusk/mountain.png new file mode 100644 index 0000000000..556db4edc1 Binary files /dev/null and b/hdr_output/output_max_linear_value/Super Mountain Dusk/mountain.png differ diff --git a/hdr_output/output_max_linear_value/Super Mountain Dusk/mountain.png.import b/hdr_output/output_max_linear_value/Super Mountain Dusk/mountain.png.import new file mode 100644 index 0000000000..282ea91b2d --- /dev/null +++ b/hdr_output/output_max_linear_value/Super Mountain Dusk/mountain.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b335ssbw6ynt6" +path="res://.godot/imported/mountain.png-2ebac19816e6eeffadf68aa242d84360.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://output_max_linear_value/Super Mountain Dusk/mountain.png" +dest_files=["res://.godot/imported/mountain.png-2ebac19816e6eeffadf68aa242d84360.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/hdr_output/output_max_linear_value/Super Mountain Dusk/public-license.txt b/hdr_output/output_max_linear_value/Super Mountain Dusk/public-license.txt new file mode 100644 index 0000000000..53af3b9ab7 --- /dev/null +++ b/hdr_output/output_max_linear_value/Super Mountain Dusk/public-license.txt @@ -0,0 +1,10 @@ +Acknowledgements + +I would like to express my sincere gratitude to everyone who has made this project +possible. I thank individuals for their ongoing support and contributions. + +License + +All assets included in this package are licensed under the Creative Commons Zero (CC0)license (https://creativecommons.org/public-domain/cc0/), which means you can use them freely in any project, whether personal orcommercial, without the need for attribution. There are no restrictions on use, modification, or redistribution of these assets. + +Luis Zuno aka Ansimuz \ No newline at end of file diff --git a/hdr_output/output_max_linear_value/spark_particle2.png b/hdr_output/output_max_linear_value/spark_particle2.png new file mode 100644 index 0000000000..b11cb691ed Binary files /dev/null and b/hdr_output/output_max_linear_value/spark_particle2.png differ diff --git a/hdr_output/output_max_linear_value/spark_particle2.png.import b/hdr_output/output_max_linear_value/spark_particle2.png.import new file mode 100644 index 0000000000..8b53abcb30 --- /dev/null +++ b/hdr_output/output_max_linear_value/spark_particle2.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cvecqn4m52x7x" +path="res://.godot/imported/spark_particle2.png-bbb493ee32a48e10ffa1a6718bf6f8ef.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://output_max_linear_value/spark_particle2.png" +dest_files=["res://.godot/imported/spark_particle2.png-bbb493ee32a48e10ffa1a6718bf6f8ef.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=true +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/hdr_output/project.godot b/hdr_output/project.godot new file mode 100644 index 0000000000..374145fed3 --- /dev/null +++ b/hdr_output/project.godot @@ -0,0 +1,27 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="HDR Output Demo" +run/main_scene="res://main.tscn" +config/features=PackedStringArray("4.6") +config/icon="res://icon.svg" + +[display] + +window/hdr/request_hdr_output=true +window/stretch/mode="canvas_items" + +[rendering] + +rendering_device/driver.windows="d3d12" +renderer/rendering_method="mobile" +viewport/hdr_2d=true diff --git a/hdr_output/setup_instructions/setup_instructions.gd b/hdr_output/setup_instructions/setup_instructions.gd new file mode 100644 index 0000000000..2a0a406f4c --- /dev/null +++ b/hdr_output/setup_instructions/setup_instructions.gd @@ -0,0 +1,5 @@ +extends RichTextLabel + + +func _on_meta_clicked(meta: Variant) -> void: + OS.shell_open(str(meta)) diff --git a/hdr_output/setup_instructions/setup_instructions.gd.uid b/hdr_output/setup_instructions/setup_instructions.gd.uid new file mode 100644 index 0000000000..3243e946ee --- /dev/null +++ b/hdr_output/setup_instructions/setup_instructions.gd.uid @@ -0,0 +1 @@ +uid://b6cwewu4wkvv5