From 4136bac55dcd87021932418a373271f942873f0f Mon Sep 17 00:00:00 2001 From: katajisto Date: Mon, 20 Oct 2025 18:17:24 +0300 Subject: [PATCH] work on ssao --- src/editor/textureDebugger.jai | 3 +- src/main.jai | 1 + src/rendering/backend_sokol.jai | 13 + src/rendering/core.jai | 9 +- src/rendering/pipelines.jai | 107 ++- src/rendering/rendering.jai | 1 + src/rendering/ssao.jai | 33 + src/shaders/jai/shader_ssao.jai | 749 ++++++++++++++++++ src/shaders/shader_ssao.glsl | 59 ++ .../UserInterfaceState.xcuserstate | Bin 31788 -> 35307 bytes 10 files changed, 967 insertions(+), 8 deletions(-) create mode 100644 src/rendering/ssao.jai create mode 100644 src/shaders/jai/shader_ssao.jai create mode 100644 src/shaders/shader_ssao.glsl diff --git a/src/editor/textureDebugger.jai b/src/editor/textureDebugger.jai index 795d810..5c1b639 100644 --- a/src/editor/textureDebugger.jai +++ b/src/editor/textureDebugger.jai @@ -7,7 +7,7 @@ theme_ptr : GR.Overall_Theme; current_pipeline : s32 = 0; current_slot : s32 = 0; -pipeline_names : []string = .["shadowmap", "reflection", "main", "position", "normal"]; +pipeline_names : []string = .["shadowmap", "reflection", "main", "position", "normal", "ssao"]; draw_subwindow_texture_debug :: (state: *GR.Subwindow_State, r: GR.Rect, data: *void) { r2 := r; @@ -29,6 +29,7 @@ draw_subwindow_texture_debug :: (state: *GR.Subwindow_State, r: GR.Rect, data: * case 2; image = g_rendertex; case 3; image = g_gbuf_position; case 4; image = g_gbuf_normal; + case 5; image = g_ssaobuf; } uiTex.tex = image; diff --git a/src/main.jai b/src/main.jai index 7b626b7..8693f0c 100644 --- a/src/main.jai +++ b/src/main.jai @@ -114,6 +114,7 @@ init_after_asset_pack :: () { init_editor(); game_init(); lworlds(); + init_rendering(); load_post_process_from_pack(); } diff --git a/src/rendering/backend_sokol.jai b/src/rendering/backend_sokol.jai index a8fc691..22aea63 100644 --- a/src/rendering/backend_sokol.jai +++ b/src/rendering/backend_sokol.jai @@ -256,6 +256,19 @@ backend_process_command_buckets :: () { current_trile_offset_index = 0; // This is not optimal, but it is nice and simple. // --- TODO: Do SSAO pass here: + sg_begin_pass(*(sg_pass.{ action = state.pass_action_clear, attachments = g_ssao_attachments})); + sg_apply_pipeline(gPipelines.ssao.pipeline); + gPipelines.ssao.bind.images[0] = g_gbuf_position; + gPipelines.ssao.bind.images[1] = g_gbuf_normal; + gPipelines.ssao.bind.images[2] = g_gbuf_position; + sg_apply_bindings(*gPipelines.ssao.bind); + ssao_fs_uniform : Ssao_Fs_Params; + mvp := create_viewproj(*camera); + ssao_fs_uniform.projection = mvp.floats; + ssao_fs_uniform.samples = g_ssao_samples; + sg_apply_uniforms(UB_ssao_fs_params, *(sg_range.{ ptr = *ssao_fs_uniform, size = size_of(type_of(ssao_fs_uniform)) })); + sg_draw(0, 6, 1); + sg_end_pass(); // 5. Main pass sg_begin_pass(*(sg_pass.{ action = state.pass_action_clear, attachments = g_rendertex_attachments})); diff --git a/src/rendering/core.jai b/src/rendering/core.jai index 7eebff2..a48bae4 100644 --- a/src/rendering/core.jai +++ b/src/rendering/core.jai @@ -2,15 +2,14 @@ #load "backend.jai"; +init_rendering :: () { + init_ssao(); +} + // Core rendering function, runs several passes. render :: () { tasks_to_commands(); process_command_buckets(); - // // @ToDo: Consider a depth pre-pass here? Research required. - // shadow_pass(); - // reflection_pass(); - // forward_pass(); - // // @ToDo: Post-processing. } #scope_file diff --git a/src/rendering/pipelines.jai b/src/rendering/pipelines.jai index 999966e..d99e40c 100644 --- a/src/rendering/pipelines.jai +++ b/src/rendering/pipelines.jai @@ -23,7 +23,10 @@ g_gbuf_normal : sg_image; g_gbuf_depth : sg_image; g_gbuf_attachments : sg_attachments; -g_ssaobuf : sg_image; +g_ssaobuf : sg_image; +g_ssao_noise_buf : sg_image; +g_ssaobuf_depth : sg_image; +g_ssao_attachments : sg_attachments; gPipelines : struct { // G-Buffer generation for SSAO and other effects @@ -43,10 +46,14 @@ gPipelines : struct { // Renders sets of triles trile : Pipeline_Binding; - // Renders the ground plane. + // Renders the ground plane. (just water) plane : Pipeline_Binding; + // Post-processing pipeline postprocess : Pipeline_Binding; + + // Renders the SSAO texture using things from the gbuffer pass. + ssao: Pipeline_Binding; } create_final_image :: () { @@ -117,6 +124,7 @@ create_pipelines :: () { create_sky_pipeline(); create_plane_pipeline(); create_postprocess_pipeline(); + create_ssao_pipeline(); create_shadowmap_image(); create_final_image(); @@ -669,6 +677,101 @@ create_postprocess_pipeline :: () { } +create_ssao_pipeline :: () { + platconf := get_plat_conf(); + pipeline: sg_pipeline_desc; + shader_desc := ssao_shader_desc(sg_query_backend()); + pipeline.shader = sg_make_shader(*shader_desc); + + pipeline.layout.attrs[ATTR_ssao_position] = .{ format = .FLOAT2 }; + pipeline.layout.attrs[ATTR_ssao_uv] = .{ format = .FLOAT2 }; + pipeline.index_type = .UINT16; + + color_state := sg_color_target_state.{ + blend = .{ + enabled = true, + src_factor_rgb = .SRC_ALPHA, + dst_factor_rgb = .ONE_MINUS_SRC_ALPHA + } + }; + + pipeline.color_count = 1; + pipeline.depth = .{ + write_enabled = true, + compare = .LESS_EQUAL, + pixel_format = .DEPTH + }; + pipeline.colors[0] = color_state; + + gPipelines.ssao.pipeline = sg_make_pipeline(*pipeline); + + quad_vertices : [16]float = .[ + -1.0, 1.0, 0.0, flip_if_plat(1.0), // top-let + -1.0, -1.0, 0.0, flip_if_plat(0.0), // bottom-let + 1.0, -1.0, 1.0, flip_if_plat(0.0), // bottom-right + 1.0, 1.0, 1.0, flip_if_plat(1.0), // top-right + ]; + quad_indices : [6]u16 = .[ + 0, 1, 2, 0, 2, 3 + ]; + + vbuffer := sg_buffer_desc.{ size = size_of(float) * 16, data = .{ + ptr = quad_vertices.data, + size = 16 * 4 + }}; + ibuffer := sg_buffer_desc.{ size = size_of(u16) * 6, data = .{ + ptr = quad_indices.data, + size = 6 * 2 + }, + type = .INDEXBUFFER, + }; + + gPipelines.ssao.bind.vertex_buffers[0] = sg_make_buffer(*vbuffer); + gPipelines.ssao.bind.index_buffer = sg_make_buffer(*ibuffer); + gPipelines.ssao.bind.samplers[0] = sg_make_sampler(*(sg_sampler_desc.{ + wrap_u = .CLAMP_TO_EDGE, + wrap_v = .CLAMP_TO_EDGE, + min_filter = .NEAREST, + mag_filter = .NEAREST, + })); + + w,h := get_render_size(); + img_desc := sg_image_desc.{ + width = w, + height = h, + render_target = true, + }; + img_desc.sample_count = 1; + g_ssaobuf = sg_make_image(*img_desc); + img_desc = sg_image_desc.{ + width = w, + height = h, + pixel_format = .DEPTH, + render_target = true, + }; + img_desc.sample_count = 1; + g_ssaobuf_depth = sg_make_image(*img_desc); + + attachmentsDesc := sg_attachments_desc.{ + colors[0].image = g_ssaobuf, + depth_stencil.image = g_ssaobuf_depth + }; + sg_destroy_attachments(g_ssao_attachments); + g_ssao_attachments = sg_make_attachments(*attachmentsDesc); + + imgdata : sg_image_data; + imgdata.subimage[0][0] = .{g_ssao_noise.data, cast(u64) (16*4)}; + texdesc : sg_image_desc = .{ + render_target = false, + width = 4, + height = 4, + pixel_format = sg_pixel_format.RGBA8, + sample_count = 1, + data = imgdata + }; + g_ssao_noise_buf = sg_make_image(*texdesc); +} + init_plane_textures :: () { gPipelines.plane.bind.images[3] = create_texture_from_pack("./resources/utiltex/water.png"); } diff --git a/src/rendering/rendering.jai b/src/rendering/rendering.jai index 003930a..d85b7b8 100644 --- a/src/rendering/rendering.jai +++ b/src/rendering/rendering.jai @@ -8,6 +8,7 @@ */ #load "sky.jai"; +#load "ssao.jai"; #load "core.jai"; #load "tasks.jai"; #load "camera.jai"; diff --git a/src/rendering/ssao.jai b/src/rendering/ssao.jai new file mode 100644 index 0000000..17fd032 --- /dev/null +++ b/src/rendering/ssao.jai @@ -0,0 +1,33 @@ +#scope_file + +Random :: #import "Random"; + +#scope_export + +g_ssao_samples : [64][4]float; +g_ssao_noise : [16*4]float; + +init_ssao :: () { + for 0..63 { + vec := Vector3.{ + Random.random_get_zero_to_one() * 2 - 1, + Random.random_get_zero_to_one() * 2 - 1, + Random.random_get_zero_to_one(), + }; + vec = normalize(vec); + vec *= Random.random_get_zero_to_one(); + scale := cast(float)it/64.0; + scale = lerp(0.1, 1.0, scale*scale); + vec *= scale; + g_ssao_samples[it][0] = vec.x; + g_ssao_samples[it][1] = vec.y; + g_ssao_samples[it][2] = vec.z; + g_ssao_samples[it][3] = 0; + } + for 0..15 { + g_ssao_noise[it*4+0] = Random.random_get_zero_to_one() * 2 - 1; + g_ssao_noise[it*4+1] = Random.random_get_zero_to_one() * 2 - 1; + g_ssao_noise[it*4+2] = 0.0; + g_ssao_noise[it*4+3] = 0.0; + } +} diff --git a/src/shaders/jai/shader_ssao.jai b/src/shaders/jai/shader_ssao.jai new file mode 100644 index 0000000..d1d18dc --- /dev/null +++ b/src/shaders/jai/shader_ssao.jai @@ -0,0 +1,749 @@ +/* + #version:1# (machine generated, don't edit!) + + Generated by sokol-shdc (https://github.com/floooh/sokol-tools) + + Cmdline: + sokol-shdc -i shader_ssao.glsl -o ./jai/shader_ssao.jai -l glsl430:glsl300es:metal_macos -f sokol_jai + + Overview: + ========= + Shader program: 'ssao': + Get shader desc: ssao_shader_desc(sg_query_backend()) + Vertex Shader: vs_ssao + Fragment Shader: fs_ssao + Attributes: + ATTR_ssao_position => 0 + ATTR_ssao_uv => 1 + Bindings: + Uniform block 'ssao_fs_params': + Jai struct: Ssao_Fs_Params + Bind slot: UB_ssao_fs_params => 1 + Image 'g_position': + Image type: ._2D + Sample type: .FLOAT + Multisampled: false + Bind slot: IMG_g_position => 0 + Image 'g_normal': + Image type: ._2D + Sample type: .FLOAT + Multisampled: false + Bind slot: IMG_g_normal => 1 + Image 'tex_noise': + Image type: ._2D + Sample type: .FLOAT + Multisampled: false + Bind slot: IMG_tex_noise => 2 + Sampler 'ssao_smp': + Type: .FILTERING + Bind slot: SMP_ssao_smp => 0 +*/ +ATTR_ssao_position :: 0; +ATTR_ssao_uv :: 1; +UB_ssao_fs_params :: 1; +IMG_g_position :: 0; +IMG_g_normal :: 1; +IMG_tex_noise :: 2; +SMP_ssao_smp :: 0; +Ssao_Fs_Params :: struct { + projection: [16]float; + samples: [64][4]float; +}; +/* + #version 430 + + layout(location = 0) in vec2 position; + layout(location = 0) out vec2 quad_uv; + layout(location = 1) in vec2 uv; + + void main() + { + gl_Position = vec4(position, 0.0, 1.0); + quad_uv = uv; + } + +*/ +vs_ssao_source_glsl430 := u8.[ + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x33,0x30,0x0a,0x0a,0x6c,0x61, + 0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, + 0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f,0x73,0x69,0x74, + 0x69,0x6f,0x6e,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, + 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65, + 0x63,0x32,0x20,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f, + 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29, + 0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x0a,0x76,0x6f, + 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, + 0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65, + 0x63,0x34,0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30, + 0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x71,0x75,0x61,0x64, + 0x5f,0x75,0x76,0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +]; +/* + #version 430 + + vec4 _204; + + uniform vec4 ssao_fs_params[68]; + layout(binding = 16) uniform sampler2D g_position_ssao_smp; + layout(binding = 17) uniform sampler2D g_normal_ssao_smp; + layout(binding = 18) uniform sampler2D tex_noise_ssao_smp; + + layout(location = 0) in vec2 quad_uv; + layout(location = 0) out vec4 out_color; + + void main() + { + vec4 _25 = texture(g_position_ssao_smp, quad_uv); + vec3 _26 = _25.xyz; + vec3 _35 = normalize(texture(g_normal_ssao_smp, quad_uv).xyz); + vec3 _51 = normalize(texture(tex_noise_ssao_smp, quad_uv * vec2(320.0, 180.0)).xyz); + vec3 _60 = normalize(_51 - (_35 * dot(_51, _35))); + mat3 _85 = mat3(_60, cross(_35, _60), _35); + float occlusion = 0.0; + for (int i = 0; i < 64; i++) + { + vec3 _119 = _26 + (_85 * ssao_fs_params[i * 1 + 4].xyz); + vec4 _131 = mat4(ssao_fs_params[0], ssao_fs_params[1], ssao_fs_params[2], ssao_fs_params[3]) * vec4(_119, 1.0); + vec2 _138 = _131.xy / vec2(_131.w); + vec4 _192; + _192.x = _138.x; + _192.y = _138.y; + vec2 _150 = (_192.xy * 0.5) + vec2(0.5); + vec4 _196; + _196.x = _150.x; + _196.y = _150.y; + vec4 _161 = texture(g_position_ssao_smp, _196.xy); + float _163 = _161.z; + occlusion += (float(_163 >= _119.z) * smoothstep(0.0, 1.0, 1.0 - (_25.z - _163))); + } + float _182 = occlusion; + float _185 = 1.0 - (_182 * 0.015625); + occlusion = _185; + out_color = vec4(_185, _185, _185, 1.0); + } + +*/ +fs_ssao_source_glsl430 := u8.[ + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x33,0x30,0x0a,0x0a,0x76,0x65, + 0x63,0x34,0x20,0x5f,0x32,0x30,0x34,0x3b,0x0a,0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72, + 0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x73,0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70, + 0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75, + 0x74,0x28,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x20,0x3d,0x20,0x31,0x36,0x29,0x20, + 0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32, + 0x44,0x20,0x67,0x5f,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x73,0x61, + 0x6f,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x62,0x69, + 0x6e,0x64,0x69,0x6e,0x67,0x20,0x3d,0x20,0x31,0x37,0x29,0x20,0x75,0x6e,0x69,0x66, + 0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x67,0x5f, + 0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x3b, + 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x20, + 0x3d,0x20,0x31,0x38,0x29,0x20,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61, + 0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x74,0x65,0x78,0x5f,0x6e,0x6f,0x69,0x73, + 0x65,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79, + 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30, + 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x71,0x75,0x61,0x64,0x5f,0x75, + 0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, + 0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34, + 0x20,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69, + 0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x76, + 0x65,0x63,0x34,0x20,0x5f,0x32,0x35,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72, + 0x65,0x28,0x67,0x5f,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x73,0x61, + 0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x29,0x3b, + 0x0a,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x33,0x20,0x5f,0x32,0x36,0x20,0x3d,0x20, + 0x5f,0x32,0x35,0x2e,0x78,0x79,0x7a,0x3b,0x0a,0x20,0x20,0x20,0x20,0x76,0x65,0x63, + 0x33,0x20,0x5f,0x33,0x35,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a, + 0x65,0x28,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x67,0x5f,0x6e,0x6f,0x72,0x6d, + 0x61,0x6c,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x71,0x75,0x61, + 0x64,0x5f,0x75,0x76,0x29,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x76,0x65,0x63,0x33,0x20,0x5f,0x35,0x31,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61, + 0x6c,0x69,0x7a,0x65,0x28,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78, + 0x5f,0x6e,0x6f,0x69,0x73,0x65,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c, + 0x20,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x28, + 0x33,0x32,0x30,0x2e,0x30,0x2c,0x20,0x31,0x38,0x30,0x2e,0x30,0x29,0x29,0x2e,0x78, + 0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x33,0x20,0x5f,0x36, + 0x30,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x5f,0x35, + 0x31,0x20,0x2d,0x20,0x28,0x5f,0x33,0x35,0x20,0x2a,0x20,0x64,0x6f,0x74,0x28,0x5f, + 0x35,0x31,0x2c,0x20,0x5f,0x33,0x35,0x29,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x6d,0x61,0x74,0x33,0x20,0x5f,0x38,0x35,0x20,0x3d,0x20,0x6d,0x61,0x74,0x33,0x28, + 0x5f,0x36,0x30,0x2c,0x20,0x63,0x72,0x6f,0x73,0x73,0x28,0x5f,0x33,0x35,0x2c,0x20, + 0x5f,0x36,0x30,0x29,0x2c,0x20,0x5f,0x33,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x66,0x6c,0x6f,0x61,0x74,0x20,0x6f,0x63,0x63,0x6c,0x75,0x73,0x69,0x6f,0x6e,0x20, + 0x3d,0x20,0x30,0x2e,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28, + 0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x36, + 0x34,0x3b,0x20,0x69,0x2b,0x2b,0x29,0x0a,0x20,0x20,0x20,0x20,0x7b,0x0a,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x33,0x20,0x5f,0x31,0x31,0x39,0x20, + 0x3d,0x20,0x5f,0x32,0x36,0x20,0x2b,0x20,0x28,0x5f,0x38,0x35,0x20,0x2a,0x20,0x73, + 0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x69,0x20, + 0x2a,0x20,0x31,0x20,0x2b,0x20,0x34,0x5d,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x34,0x20,0x5f,0x31,0x33,0x31, + 0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x73,0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f, + 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c,0x20,0x73,0x73,0x61,0x6f,0x5f, + 0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x73,0x73, + 0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c, + 0x20,0x73,0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b, + 0x33,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x31,0x31,0x39,0x2c, + 0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76, + 0x65,0x63,0x32,0x20,0x5f,0x31,0x33,0x38,0x20,0x3d,0x20,0x5f,0x31,0x33,0x31,0x2e, + 0x78,0x79,0x20,0x2f,0x20,0x76,0x65,0x63,0x32,0x28,0x5f,0x31,0x33,0x31,0x2e,0x77, + 0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x34,0x20, + 0x5f,0x31,0x39,0x32,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x31, + 0x39,0x32,0x2e,0x78,0x20,0x3d,0x20,0x5f,0x31,0x33,0x38,0x2e,0x78,0x3b,0x0a,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x31,0x39,0x32,0x2e,0x79,0x20,0x3d,0x20, + 0x5f,0x31,0x33,0x38,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x76,0x65,0x63,0x32,0x20,0x5f,0x31,0x35,0x30,0x20,0x3d,0x20,0x28,0x5f,0x31,0x39, + 0x32,0x2e,0x78,0x79,0x20,0x2a,0x20,0x30,0x2e,0x35,0x29,0x20,0x2b,0x20,0x76,0x65, + 0x63,0x32,0x28,0x30,0x2e,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x76,0x65,0x63,0x34,0x20,0x5f,0x31,0x39,0x36,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x5f,0x31,0x39,0x36,0x2e,0x78,0x20,0x3d,0x20,0x5f,0x31,0x35, + 0x30,0x2e,0x78,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x31,0x39, + 0x36,0x2e,0x79,0x20,0x3d,0x20,0x5f,0x31,0x35,0x30,0x2e,0x79,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x76,0x65,0x63,0x34,0x20,0x5f,0x31,0x36,0x31,0x20, + 0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x67,0x5f,0x70,0x6f,0x73,0x69, + 0x74,0x69,0x6f,0x6e,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x5f, + 0x31,0x39,0x36,0x2e,0x78,0x79,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x31,0x36,0x33,0x20,0x3d,0x20,0x5f,0x31, + 0x36,0x31,0x2e,0x7a,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x63, + 0x63,0x6c,0x75,0x73,0x69,0x6f,0x6e,0x20,0x2b,0x3d,0x20,0x28,0x66,0x6c,0x6f,0x61, + 0x74,0x28,0x5f,0x31,0x36,0x33,0x20,0x3e,0x3d,0x20,0x5f,0x31,0x31,0x39,0x2e,0x7a, + 0x29,0x20,0x2a,0x20,0x73,0x6d,0x6f,0x6f,0x74,0x68,0x73,0x74,0x65,0x70,0x28,0x30, + 0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x20,0x2d,0x20,0x28, + 0x5f,0x32,0x35,0x2e,0x7a,0x20,0x2d,0x20,0x5f,0x31,0x36,0x33,0x29,0x29,0x29,0x3b, + 0x0a,0x20,0x20,0x20,0x20,0x7d,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, + 0x20,0x5f,0x31,0x38,0x32,0x20,0x3d,0x20,0x6f,0x63,0x63,0x6c,0x75,0x73,0x69,0x6f, + 0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x31,0x38, + 0x35,0x20,0x3d,0x20,0x31,0x2e,0x30,0x20,0x2d,0x20,0x28,0x5f,0x31,0x38,0x32,0x20, + 0x2a,0x20,0x30,0x2e,0x30,0x31,0x35,0x36,0x32,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x6f,0x63,0x63,0x6c,0x75,0x73,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x38, + 0x35,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72, + 0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x5f,0x31,0x38,0x35,0x2c,0x20,0x5f,0x31, + 0x38,0x35,0x2c,0x20,0x5f,0x31,0x38,0x35,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a, + 0x7d,0x0a,0x0a,0x00, +]; +/* + #version 300 es + + layout(location = 0) in vec2 position; + out vec2 quad_uv; + layout(location = 1) in vec2 uv; + + void main() + { + gl_Position = vec4(position, 0.0, 1.0); + quad_uv = uv; + } + +*/ +vs_ssao_source_glsl300es := u8.[ + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, + 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, + 0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x70,0x6f, + 0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32, + 0x20,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, + 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69, + 0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x75,0x76,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64, + 0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c, + 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34, + 0x28,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20, + 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x71,0x75,0x61,0x64,0x5f,0x75, + 0x76,0x20,0x3d,0x20,0x75,0x76,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +]; +/* + #version 300 es + precision mediump float; + precision highp int; + + vec4 _204; + + uniform highp vec4 ssao_fs_params[68]; + uniform highp sampler2D g_position_ssao_smp; + uniform highp sampler2D g_normal_ssao_smp; + uniform highp sampler2D tex_noise_ssao_smp; + + in highp vec2 quad_uv; + layout(location = 0) out highp vec4 out_color; + + void main() + { + highp vec4 _25 = texture(g_position_ssao_smp, quad_uv); + highp vec3 _26 = _25.xyz; + highp vec3 _35 = normalize(texture(g_normal_ssao_smp, quad_uv).xyz); + highp vec3 _51 = normalize(texture(tex_noise_ssao_smp, quad_uv * vec2(320.0, 180.0)).xyz); + highp vec3 _60 = normalize(_51 - (_35 * dot(_51, _35))); + highp mat3 _85 = mat3(_60, cross(_35, _60), _35); + highp float occlusion = 0.0; + for (int i = 0; i < 64; i++) + { + highp vec3 _119 = _26 + (_85 * ssao_fs_params[i * 1 + 4].xyz); + highp vec4 _131 = mat4(ssao_fs_params[0], ssao_fs_params[1], ssao_fs_params[2], ssao_fs_params[3]) * vec4(_119, 1.0); + highp vec2 _138 = _131.xy / vec2(_131.w); + highp vec4 _192; + _192.x = _138.x; + _192.y = _138.y; + highp vec2 _150 = (_192.xy * 0.5) + vec2(0.5); + highp vec4 _196; + _196.x = _150.x; + _196.y = _150.y; + highp vec4 _161 = texture(g_position_ssao_smp, _196.xy); + highp float _163 = _161.z; + occlusion += (float(_163 >= _119.z) * smoothstep(0.0, 1.0, 1.0 - (_25.z - _163))); + } + highp float _182 = occlusion; + highp float _185 = 1.0 - (_182 * 0.015625); + occlusion = _185; + out_color = vec4(_185, _185, _185, 1.0); + } + +*/ +fs_ssao_source_glsl300es := u8.[ + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, + 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, + 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, + 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x76, + 0x65,0x63,0x34,0x20,0x5f,0x32,0x30,0x34,0x3b,0x0a,0x0a,0x75,0x6e,0x69,0x66,0x6f, + 0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x73,0x73, + 0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x38,0x5d, + 0x3b,0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20, + 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x67,0x5f,0x70,0x6f,0x73,0x69, + 0x74,0x69,0x6f,0x6e,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x75, + 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, + 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x67,0x5f,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x5f, + 0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72, + 0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32, + 0x44,0x20,0x74,0x65,0x78,0x5f,0x6e,0x6f,0x69,0x73,0x65,0x5f,0x73,0x73,0x61,0x6f, + 0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20, + 0x76,0x65,0x63,0x32,0x20,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x3b,0x0a,0x6c,0x61, + 0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, + 0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63, + 0x34,0x20,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f, + 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, + 0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x5f,0x32,0x35,0x20,0x3d, + 0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x67,0x5f,0x70,0x6f,0x73,0x69,0x74, + 0x69,0x6f,0x6e,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x71,0x75, + 0x61,0x64,0x5f,0x75,0x76,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68, + 0x70,0x20,0x76,0x65,0x63,0x33,0x20,0x5f,0x32,0x36,0x20,0x3d,0x20,0x5f,0x32,0x35, + 0x2e,0x78,0x79,0x7a,0x3b,0x0a,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20, + 0x76,0x65,0x63,0x33,0x20,0x5f,0x33,0x35,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61, + 0x6c,0x69,0x7a,0x65,0x28,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x67,0x5f,0x6e, + 0x6f,0x72,0x6d,0x61,0x6c,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20, + 0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x29,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20, + 0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x33,0x20,0x5f,0x35, + 0x31,0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x74,0x65, + 0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x6e,0x6f,0x69,0x73,0x65,0x5f, + 0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x71,0x75,0x61,0x64,0x5f,0x75, + 0x76,0x20,0x2a,0x20,0x76,0x65,0x63,0x32,0x28,0x33,0x32,0x30,0x2e,0x30,0x2c,0x20, + 0x31,0x38,0x30,0x2e,0x30,0x29,0x29,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x33,0x20,0x5f,0x36,0x30, + 0x20,0x3d,0x20,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x5f,0x35,0x31, + 0x20,0x2d,0x20,0x28,0x5f,0x33,0x35,0x20,0x2a,0x20,0x64,0x6f,0x74,0x28,0x5f,0x35, + 0x31,0x2c,0x20,0x5f,0x33,0x35,0x29,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x68, + 0x69,0x67,0x68,0x70,0x20,0x6d,0x61,0x74,0x33,0x20,0x5f,0x38,0x35,0x20,0x3d,0x20, + 0x6d,0x61,0x74,0x33,0x28,0x5f,0x36,0x30,0x2c,0x20,0x63,0x72,0x6f,0x73,0x73,0x28, + 0x5f,0x33,0x35,0x2c,0x20,0x5f,0x36,0x30,0x29,0x2c,0x20,0x5f,0x33,0x35,0x29,0x3b, + 0x0a,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61,0x74, + 0x20,0x6f,0x63,0x63,0x6c,0x75,0x73,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x2e,0x30, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69, + 0x20,0x3d,0x20,0x30,0x3b,0x20,0x69,0x20,0x3c,0x20,0x36,0x34,0x3b,0x20,0x69,0x2b, + 0x2b,0x29,0x0a,0x20,0x20,0x20,0x20,0x7b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x33,0x20,0x5f,0x31,0x31,0x39, + 0x20,0x3d,0x20,0x5f,0x32,0x36,0x20,0x2b,0x20,0x28,0x5f,0x38,0x35,0x20,0x2a,0x20, + 0x73,0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x69, + 0x20,0x2a,0x20,0x31,0x20,0x2b,0x20,0x34,0x5d,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65, + 0x63,0x34,0x20,0x5f,0x31,0x33,0x31,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x73, + 0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d, + 0x2c,0x20,0x73,0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73, + 0x5b,0x31,0x5d,0x2c,0x20,0x73,0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72, + 0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x73,0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f, + 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63, + 0x34,0x28,0x5f,0x31,0x31,0x39,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32, + 0x20,0x5f,0x31,0x33,0x38,0x20,0x3d,0x20,0x5f,0x31,0x33,0x31,0x2e,0x78,0x79,0x20, + 0x2f,0x20,0x76,0x65,0x63,0x32,0x28,0x5f,0x31,0x33,0x31,0x2e,0x77,0x29,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65, + 0x63,0x34,0x20,0x5f,0x31,0x39,0x32,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x5f,0x31,0x39,0x32,0x2e,0x78,0x20,0x3d,0x20,0x5f,0x31,0x33,0x38,0x2e,0x78, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x31,0x39,0x32,0x2e,0x79, + 0x20,0x3d,0x20,0x5f,0x31,0x33,0x38,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20,0x5f,0x31, + 0x35,0x30,0x20,0x3d,0x20,0x28,0x5f,0x31,0x39,0x32,0x2e,0x78,0x79,0x20,0x2a,0x20, + 0x30,0x2e,0x35,0x29,0x20,0x2b,0x20,0x76,0x65,0x63,0x32,0x28,0x30,0x2e,0x35,0x29, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20, + 0x76,0x65,0x63,0x34,0x20,0x5f,0x31,0x39,0x36,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x5f,0x31,0x39,0x36,0x2e,0x78,0x20,0x3d,0x20,0x5f,0x31,0x35,0x30, + 0x2e,0x78,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x31,0x39,0x36, + 0x2e,0x79,0x20,0x3d,0x20,0x5f,0x31,0x35,0x30,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x34,0x20, + 0x5f,0x31,0x36,0x31,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x67, + 0x5f,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x5f,0x73,0x73,0x61,0x6f,0x5f,0x73, + 0x6d,0x70,0x2c,0x20,0x5f,0x31,0x39,0x36,0x2e,0x78,0x79,0x29,0x3b,0x0a,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61, + 0x74,0x20,0x5f,0x31,0x36,0x33,0x20,0x3d,0x20,0x5f,0x31,0x36,0x31,0x2e,0x7a,0x3b, + 0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x63,0x63,0x6c,0x75,0x73,0x69, + 0x6f,0x6e,0x20,0x2b,0x3d,0x20,0x28,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x31,0x36, + 0x33,0x20,0x3e,0x3d,0x20,0x5f,0x31,0x31,0x39,0x2e,0x7a,0x29,0x20,0x2a,0x20,0x73, + 0x6d,0x6f,0x6f,0x74,0x68,0x73,0x74,0x65,0x70,0x28,0x30,0x2e,0x30,0x2c,0x20,0x31, + 0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x20,0x2d,0x20,0x28,0x5f,0x32,0x35,0x2e,0x7a, + 0x20,0x2d,0x20,0x5f,0x31,0x36,0x33,0x29,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, + 0x7d,0x0a,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x66,0x6c,0x6f,0x61, + 0x74,0x20,0x5f,0x31,0x38,0x32,0x20,0x3d,0x20,0x6f,0x63,0x63,0x6c,0x75,0x73,0x69, + 0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x20,0x5f,0x31,0x38,0x35,0x20,0x3d,0x20,0x31,0x2e,0x30,0x20,0x2d, + 0x20,0x28,0x5f,0x31,0x38,0x32,0x20,0x2a,0x20,0x30,0x2e,0x30,0x31,0x35,0x36,0x32, + 0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x63,0x63,0x6c,0x75,0x73,0x69,0x6f, + 0x6e,0x20,0x3d,0x20,0x5f,0x31,0x38,0x35,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75, + 0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x5f, + 0x31,0x38,0x35,0x2c,0x20,0x5f,0x31,0x38,0x35,0x2c,0x20,0x5f,0x31,0x38,0x35,0x2c, + 0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +]; +/* + #include + #include + + using namespace metal; + + struct main0_out + { + float2 quad_uv [[user(locn0)]]; + float4 gl_Position [[position]]; + }; + + struct main0_in + { + float2 position [[attribute(0)]]; + float2 uv [[attribute(1)]]; + }; + + vertex main0_out main0(main0_in in [[stage_in]]) + { + main0_out out = {}; + out.gl_Position = float4(in.position, 0.0, 1.0); + out.quad_uv = in.uv; + return out; + } + +*/ +vs_ssao_source_metal_macos := u8.[ + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, + 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x32,0x20,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x20,0x5b,0x5b, + 0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20, + 0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73, + 0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, + 0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, + 0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x32,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b, + 0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x75,0x76,0x20,0x5b,0x5b, + 0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b,0x0a, + 0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74,0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30, + 0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30, + 0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69, + 0x6e,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30, + 0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20, + 0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69, + 0x6f,0x6e,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x70, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e, + 0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x71,0x75,0x61,0x64, + 0x5f,0x75,0x76,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x75,0x76,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a, + 0x00, +]; +/* + #include + #include + + using namespace metal; + + struct ssao_fs_params + { + float4x4 projection; + float4 samples[64]; + }; + + constant float4 _204 = {}; + + struct main0_out + { + float4 out_color [[color(0)]]; + }; + + struct main0_in + { + float2 quad_uv [[user(locn0)]]; + }; + + fragment main0_out main0(main0_in in [[stage_in]], constant ssao_fs_params& _109 [[buffer(0)]], texture2d g_position [[texture(0)]], texture2d g_normal [[texture(1)]], texture2d tex_noise [[texture(2)]], sampler ssao_smp [[sampler(0)]]) + { + main0_out out = {}; + float4 _25 = g_position.sample(ssao_smp, in.quad_uv); + float3 _26 = _25.xyz; + float3 _35 = fast::normalize(g_normal.sample(ssao_smp, in.quad_uv).xyz); + float3 _51 = fast::normalize(tex_noise.sample(ssao_smp, (in.quad_uv * float2(320.0, 180.0))).xyz); + float3 _60 = fast::normalize(_51 - (_35 * dot(_51, _35))); + float3x3 _85 = float3x3(_60, cross(_35, _60), _35); + float occlusion = 0.0; + for (int i = 0; i < 64; i++) + { + float3 _119 = _26 + (_85 * _109.samples[i].xyz); + float4 _131 = _109.projection * float4(_119, 1.0); + float2 _138 = _131.xy / float2(_131.w); + float4 _192; + _192.x = _138.x; + _192.y = _138.y; + float2 _150 = (_192.xy * 0.5) + float2(0.5); + float4 _196; + _196.x = _150.x; + _196.y = _150.y; + float4 _161 = g_position.sample(ssao_smp, _196.xy); + float _163 = _161.z; + occlusion += (float(_163 >= _119.z) * smoothstep(0.0, 1.0, 1.0 - (_25.z - _163))); + } + float _182 = occlusion; + float _185 = 1.0 - (_182 * 0.015625); + occlusion = _185; + out.out_color = float4(_185, _185, _185, 1.0); + return out; + } + +*/ +fs_ssao_source_metal_macos := u8.[ + 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, + 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, + 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, + 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, + 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x73, + 0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x0a,0x7b,0x0a, + 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x78,0x34,0x20,0x70,0x72,0x6f, + 0x6a,0x65,0x63,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, + 0x61,0x74,0x34,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x73,0x5b,0x36,0x34,0x5d,0x3b, + 0x0a,0x7d,0x3b,0x0a,0x0a,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x34,0x20,0x5f,0x32,0x30,0x34,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a, + 0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75, + 0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x6f, + 0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72, + 0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63, + 0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20, + 0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x20, + 0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b, + 0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d,0x61, + 0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61, + 0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67, + 0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20,0x63,0x6f,0x6e,0x73,0x74,0x61,0x6e,0x74, + 0x20,0x73,0x73,0x61,0x6f,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x26, + 0x20,0x5f,0x31,0x30,0x39,0x20,0x5b,0x5b,0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30, + 0x29,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66, + 0x6c,0x6f,0x61,0x74,0x3e,0x20,0x67,0x5f,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, + 0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d,0x2c, + 0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74, + 0x3e,0x20,0x67,0x5f,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x20,0x5b,0x5b,0x74,0x65,0x78, + 0x74,0x75,0x72,0x65,0x28,0x31,0x29,0x5d,0x5d,0x2c,0x20,0x74,0x65,0x78,0x74,0x75, + 0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e,0x20,0x74,0x65,0x78,0x5f, + 0x6e,0x6f,0x69,0x73,0x65,0x20,0x5b,0x5b,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28, + 0x32,0x29,0x5d,0x5d,0x2c,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x20,0x73,0x73, + 0x61,0x6f,0x5f,0x73,0x6d,0x70,0x20,0x5b,0x5b,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72, + 0x28,0x30,0x29,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69, + 0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b, + 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x32,0x35,0x20, + 0x3d,0x20,0x67,0x5f,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2e,0x73,0x61,0x6d, + 0x70,0x6c,0x65,0x28,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x69,0x6e, + 0x2e,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6c,0x6f,0x61,0x74,0x33,0x20,0x5f,0x32,0x36,0x20,0x3d,0x20,0x5f,0x32,0x35,0x2e, + 0x78,0x79,0x7a,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x20, + 0x5f,0x33,0x35,0x20,0x3d,0x20,0x66,0x61,0x73,0x74,0x3a,0x3a,0x6e,0x6f,0x72,0x6d, + 0x61,0x6c,0x69,0x7a,0x65,0x28,0x67,0x5f,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x2e,0x73, + 0x61,0x6d,0x70,0x6c,0x65,0x28,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20, + 0x69,0x6e,0x2e,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x29,0x2e,0x78,0x79,0x7a,0x29, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33,0x20,0x5f,0x35,0x31, + 0x20,0x3d,0x20,0x66,0x61,0x73,0x74,0x3a,0x3a,0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69, + 0x7a,0x65,0x28,0x74,0x65,0x78,0x5f,0x6e,0x6f,0x69,0x73,0x65,0x2e,0x73,0x61,0x6d, + 0x70,0x6c,0x65,0x28,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x28,0x69, + 0x6e,0x2e,0x71,0x75,0x61,0x64,0x5f,0x75,0x76,0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61, + 0x74,0x32,0x28,0x33,0x32,0x30,0x2e,0x30,0x2c,0x20,0x31,0x38,0x30,0x2e,0x30,0x29, + 0x29,0x29,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, + 0x61,0x74,0x33,0x20,0x5f,0x36,0x30,0x20,0x3d,0x20,0x66,0x61,0x73,0x74,0x3a,0x3a, + 0x6e,0x6f,0x72,0x6d,0x61,0x6c,0x69,0x7a,0x65,0x28,0x5f,0x35,0x31,0x20,0x2d,0x20, + 0x28,0x5f,0x33,0x35,0x20,0x2a,0x20,0x64,0x6f,0x74,0x28,0x5f,0x35,0x31,0x2c,0x20, + 0x5f,0x33,0x35,0x29,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, + 0x74,0x33,0x78,0x33,0x20,0x5f,0x38,0x35,0x20,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74, + 0x33,0x78,0x33,0x28,0x5f,0x36,0x30,0x2c,0x20,0x63,0x72,0x6f,0x73,0x73,0x28,0x5f, + 0x33,0x35,0x2c,0x20,0x5f,0x36,0x30,0x29,0x2c,0x20,0x5f,0x33,0x35,0x29,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x6f,0x63,0x63,0x6c,0x75,0x73, + 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x2e,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66, + 0x6f,0x72,0x20,0x28,0x69,0x6e,0x74,0x20,0x69,0x20,0x3d,0x20,0x30,0x3b,0x20,0x69, + 0x20,0x3c,0x20,0x36,0x34,0x3b,0x20,0x69,0x2b,0x2b,0x29,0x0a,0x20,0x20,0x20,0x20, + 0x7b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x33, + 0x20,0x5f,0x31,0x31,0x39,0x20,0x3d,0x20,0x5f,0x32,0x36,0x20,0x2b,0x20,0x28,0x5f, + 0x38,0x35,0x20,0x2a,0x20,0x5f,0x31,0x30,0x39,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65, + 0x73,0x5b,0x69,0x5d,0x2e,0x78,0x79,0x7a,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x31,0x33,0x31,0x20,0x3d, + 0x20,0x5f,0x31,0x30,0x39,0x2e,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x69,0x6f,0x6e, + 0x20,0x2a,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x5f,0x31,0x31,0x39,0x2c,0x20, + 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x32,0x20,0x5f,0x31,0x33,0x38,0x20,0x3d,0x20,0x5f,0x31,0x33,0x31, + 0x2e,0x78,0x79,0x20,0x2f,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x5f,0x31,0x33, + 0x31,0x2e,0x77,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c, + 0x6f,0x61,0x74,0x34,0x20,0x5f,0x31,0x39,0x32,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x5f,0x31,0x39,0x32,0x2e,0x78,0x20,0x3d,0x20,0x5f,0x31,0x33,0x38, + 0x2e,0x78,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x31,0x39,0x32, + 0x2e,0x79,0x20,0x3d,0x20,0x5f,0x31,0x33,0x38,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x5f,0x31,0x35,0x30, + 0x20,0x3d,0x20,0x28,0x5f,0x31,0x39,0x32,0x2e,0x78,0x79,0x20,0x2a,0x20,0x30,0x2e, + 0x35,0x29,0x20,0x2b,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x28,0x30,0x2e,0x35,0x29, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, + 0x20,0x5f,0x31,0x39,0x36,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f, + 0x31,0x39,0x36,0x2e,0x78,0x20,0x3d,0x20,0x5f,0x31,0x35,0x30,0x2e,0x78,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x5f,0x31,0x39,0x36,0x2e,0x79,0x20,0x3d, + 0x20,0x5f,0x31,0x35,0x30,0x2e,0x79,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x5f,0x31,0x36,0x31,0x20,0x3d,0x20,0x67, + 0x5f,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2e,0x73,0x61,0x6d,0x70,0x6c,0x65, + 0x28,0x73,0x73,0x61,0x6f,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x5f,0x31,0x39,0x36,0x2e, + 0x78,0x79,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f, + 0x61,0x74,0x20,0x5f,0x31,0x36,0x33,0x20,0x3d,0x20,0x5f,0x31,0x36,0x31,0x2e,0x7a, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x6f,0x63,0x63,0x6c,0x75,0x73, + 0x69,0x6f,0x6e,0x20,0x2b,0x3d,0x20,0x28,0x66,0x6c,0x6f,0x61,0x74,0x28,0x5f,0x31, + 0x36,0x33,0x20,0x3e,0x3d,0x20,0x5f,0x31,0x31,0x39,0x2e,0x7a,0x29,0x20,0x2a,0x20, + 0x73,0x6d,0x6f,0x6f,0x74,0x68,0x73,0x74,0x65,0x70,0x28,0x30,0x2e,0x30,0x2c,0x20, + 0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x20,0x2d,0x20,0x28,0x5f,0x32,0x35,0x2e, + 0x7a,0x20,0x2d,0x20,0x5f,0x31,0x36,0x33,0x29,0x29,0x29,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x7d,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x31,0x38, + 0x32,0x20,0x3d,0x20,0x6f,0x63,0x63,0x6c,0x75,0x73,0x69,0x6f,0x6e,0x3b,0x0a,0x20, + 0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x5f,0x31,0x38,0x35,0x20,0x3d,0x20, + 0x31,0x2e,0x30,0x20,0x2d,0x20,0x28,0x5f,0x31,0x38,0x32,0x20,0x2a,0x20,0x30,0x2e, + 0x30,0x31,0x35,0x36,0x32,0x35,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x63,0x63, + 0x6c,0x75,0x73,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x5f,0x31,0x38,0x35,0x3b,0x0a,0x20, + 0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x6f,0x75,0x74,0x5f,0x63,0x6f,0x6c,0x6f,0x72, + 0x20,0x3d,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x28,0x5f,0x31,0x38,0x35,0x2c,0x20, + 0x5f,0x31,0x38,0x35,0x2c,0x20,0x5f,0x31,0x38,0x35,0x2c,0x20,0x31,0x2e,0x30,0x29, + 0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74, + 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, +]; +ssao_shader_desc :: (backend: sg_backend) -> sg_shader_desc { + desc: sg_shader_desc; + desc.label = "ssao_shader"; + if backend == { + case .GLCORE; + desc.vertex_func.source = xx *vs_ssao_source_glsl430; + desc.vertex_func.entry = "main"; + desc.fragment_func.source = xx *fs_ssao_source_glsl430; + desc.fragment_func.entry = "main"; + desc.attrs[0].base_type = .FLOAT; + desc.attrs[0].glsl_name = "position"; + desc.attrs[1].base_type = .FLOAT; + desc.attrs[1].glsl_name = "uv"; + desc.uniform_blocks[1].stage = .FRAGMENT; + desc.uniform_blocks[1].layout = .STD140; + desc.uniform_blocks[1].size = 1088; + desc.uniform_blocks[1].glsl_uniforms[0].type = .FLOAT4; + desc.uniform_blocks[1].glsl_uniforms[0].array_count = 68; + desc.uniform_blocks[1].glsl_uniforms[0].glsl_name = "ssao_fs_params"; + desc.images[0].stage = .FRAGMENT; + desc.images[0].multisampled = false; + desc.images[0].image_type = ._2D; + desc.images[0].sample_type = .FLOAT; + desc.images[1].stage = .FRAGMENT; + desc.images[1].multisampled = false; + desc.images[1].image_type = ._2D; + desc.images[1].sample_type = .FLOAT; + desc.images[2].stage = .FRAGMENT; + desc.images[2].multisampled = false; + desc.images[2].image_type = ._2D; + desc.images[2].sample_type = .FLOAT; + desc.samplers[0].stage = .FRAGMENT; + desc.samplers[0].sampler_type = .FILTERING; + desc.image_sampler_pairs[0].stage = .FRAGMENT; + desc.image_sampler_pairs[0].image_slot = 0; + desc.image_sampler_pairs[0].sampler_slot = 0; + desc.image_sampler_pairs[0].glsl_name = "g_position_ssao_smp"; + desc.image_sampler_pairs[1].stage = .FRAGMENT; + desc.image_sampler_pairs[1].image_slot = 1; + desc.image_sampler_pairs[1].sampler_slot = 0; + desc.image_sampler_pairs[1].glsl_name = "g_normal_ssao_smp"; + desc.image_sampler_pairs[2].stage = .FRAGMENT; + desc.image_sampler_pairs[2].image_slot = 2; + desc.image_sampler_pairs[2].sampler_slot = 0; + desc.image_sampler_pairs[2].glsl_name = "tex_noise_ssao_smp"; + case .GLES3; + desc.vertex_func.source = xx *vs_ssao_source_glsl300es; + desc.vertex_func.entry = "main"; + desc.fragment_func.source = xx *fs_ssao_source_glsl300es; + desc.fragment_func.entry = "main"; + desc.attrs[0].base_type = .FLOAT; + desc.attrs[0].glsl_name = "position"; + desc.attrs[1].base_type = .FLOAT; + desc.attrs[1].glsl_name = "uv"; + desc.uniform_blocks[1].stage = .FRAGMENT; + desc.uniform_blocks[1].layout = .STD140; + desc.uniform_blocks[1].size = 1088; + desc.uniform_blocks[1].glsl_uniforms[0].type = .FLOAT4; + desc.uniform_blocks[1].glsl_uniforms[0].array_count = 68; + desc.uniform_blocks[1].glsl_uniforms[0].glsl_name = "ssao_fs_params"; + desc.images[0].stage = .FRAGMENT; + desc.images[0].multisampled = false; + desc.images[0].image_type = ._2D; + desc.images[0].sample_type = .FLOAT; + desc.images[1].stage = .FRAGMENT; + desc.images[1].multisampled = false; + desc.images[1].image_type = ._2D; + desc.images[1].sample_type = .FLOAT; + desc.images[2].stage = .FRAGMENT; + desc.images[2].multisampled = false; + desc.images[2].image_type = ._2D; + desc.images[2].sample_type = .FLOAT; + desc.samplers[0].stage = .FRAGMENT; + desc.samplers[0].sampler_type = .FILTERING; + desc.image_sampler_pairs[0].stage = .FRAGMENT; + desc.image_sampler_pairs[0].image_slot = 0; + desc.image_sampler_pairs[0].sampler_slot = 0; + desc.image_sampler_pairs[0].glsl_name = "g_position_ssao_smp"; + desc.image_sampler_pairs[1].stage = .FRAGMENT; + desc.image_sampler_pairs[1].image_slot = 1; + desc.image_sampler_pairs[1].sampler_slot = 0; + desc.image_sampler_pairs[1].glsl_name = "g_normal_ssao_smp"; + desc.image_sampler_pairs[2].stage = .FRAGMENT; + desc.image_sampler_pairs[2].image_slot = 2; + desc.image_sampler_pairs[2].sampler_slot = 0; + desc.image_sampler_pairs[2].glsl_name = "tex_noise_ssao_smp"; + case .METAL_MACOS; + desc.vertex_func.source = xx *vs_ssao_source_metal_macos; + desc.vertex_func.entry = "main0"; + desc.fragment_func.source = xx *fs_ssao_source_metal_macos; + desc.fragment_func.entry = "main0"; + desc.attrs[0].base_type = .FLOAT; + desc.attrs[1].base_type = .FLOAT; + desc.uniform_blocks[1].stage = .FRAGMENT; + desc.uniform_blocks[1].layout = .STD140; + desc.uniform_blocks[1].size = 1088; + desc.uniform_blocks[1].msl_buffer_n = 0; + desc.images[0].stage = .FRAGMENT; + desc.images[0].multisampled = false; + desc.images[0].image_type = ._2D; + desc.images[0].sample_type = .FLOAT; + desc.images[0].msl_texture_n = 0; + desc.images[1].stage = .FRAGMENT; + desc.images[1].multisampled = false; + desc.images[1].image_type = ._2D; + desc.images[1].sample_type = .FLOAT; + desc.images[1].msl_texture_n = 1; + desc.images[2].stage = .FRAGMENT; + desc.images[2].multisampled = false; + desc.images[2].image_type = ._2D; + desc.images[2].sample_type = .FLOAT; + desc.images[2].msl_texture_n = 2; + desc.samplers[0].stage = .FRAGMENT; + desc.samplers[0].sampler_type = .FILTERING; + desc.samplers[0].msl_sampler_n = 0; + desc.image_sampler_pairs[0].stage = .FRAGMENT; + desc.image_sampler_pairs[0].image_slot = 0; + desc.image_sampler_pairs[0].sampler_slot = 0; + desc.image_sampler_pairs[1].stage = .FRAGMENT; + desc.image_sampler_pairs[1].image_slot = 1; + desc.image_sampler_pairs[1].sampler_slot = 0; + desc.image_sampler_pairs[2].stage = .FRAGMENT; + desc.image_sampler_pairs[2].image_slot = 2; + desc.image_sampler_pairs[2].sampler_slot = 0; + } + return desc; +} diff --git a/src/shaders/shader_ssao.glsl b/src/shaders/shader_ssao.glsl new file mode 100644 index 0000000..5493355 --- /dev/null +++ b/src/shaders/shader_ssao.glsl @@ -0,0 +1,59 @@ +@vs vs_ssao +in vec2 position; +in vec2 uv; + +out vec2 quad_uv; + +void main() { + gl_Position = vec4(position, 0.0, 1.0); + quad_uv = uv; +} +@end + +@fs fs_ssao + +layout(binding=0) uniform texture2D g_position; +layout(binding=1) uniform texture2D g_normal; +layout(binding=2) uniform texture2D tex_noise; + +layout(binding=0) uniform sampler ssao_smp; + +layout(binding=1) uniform ssao_fs_params { + mat4 projection; + vec4 samples[64]; +}; + +in vec2 quad_uv; +out vec4 out_color; + +void main() { + vec3 frag_pos = texture(sampler2D(g_position, ssao_smp), quad_uv).xyz; + vec3 normal = normalize(texture(sampler2D(g_normal, ssao_smp), quad_uv).rgb); + vec2 noise_scale = vec2(1280.0/4.0, 720.0/4.0); // @Incomplete: get screen size + vec3 random_vec = normalize(texture(sampler2D(tex_noise, ssao_smp), quad_uv * noise_scale).xyz); + + vec3 tangent = normalize(random_vec - normal * dot(random_vec, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 tbn = mat3(tangent, bitangent, normal); + + float occlusion = 0.0; + for (int i = 0; i < 64; ++i) { + vec3 sample_pos = tbn * samples[i].xyz; + sample_pos = frag_pos + sample_pos; + + vec4 offset = vec4(sample_pos, 1.0); + offset = projection * offset; + offset.xy /= offset.w; + offset.xy = offset.xy * 0.5 + 0.5; + + float sample_depth = texture(sampler2D(g_position, ssao_smp), offset.xy).z; + float range_check = smoothstep(0.0, 1.0, 1.0 - (frag_pos.z - sample_depth)); + occlusion += (sample_depth >= sample_pos.z ? 1.0 : 0.0) * range_check; + } + + occlusion = 1.0 - (occlusion / 64.0); + out_color = vec4(occlusion, occlusion, occlusion, 1.0); +} +@end + +@program ssao vs_ssao fs_ssao diff --git a/trueno/trueno.xcodeproj/project.xcworkspace/xcuserdata/tuomas.katajisto.xcuserdatad/UserInterfaceState.xcuserstate b/trueno/trueno.xcodeproj/project.xcworkspace/xcuserdata/tuomas.katajisto.xcuserdatad/UserInterfaceState.xcuserstate index 17f753529bd1e550d41d0332af2d6f61365054ed..a1fe4b1d9b2496f9e6df3ccb22f25df236cea76b 100644 GIT binary patch delta 18085 zcmch;2UwIx+dsN9PhUV5P@2*^ZlU)ky)C^XJSk=b~lN!M!+78#uB5( z*h`GDx2Unj*o{4QJ+lj_`SSkX|M{-#T*sAVcb=JhX72lU*BMqm1GlwsdO0LaW>mh^ zEC(yVH((`L1-=EV!5Z)#SPRyH60ja@06V}=unX)4d%!Q?Aovv=0>{8{a2ospu7ca( z0eA==fv4alcm)LzKnl{3gF@IB_Jh{Y7CJz8I1oyqFZ6@aFb2lLI2aETU?NO`X)qn; z!va{SfyJ-{R>5l62%De^eg-GO$#4ps3a7#8a0Z+SweWNJ1^g1ug7e`5*acU?Z{cdV z27U+E!XM#Q_!B$;e}M<#uka8&3(vvx@OO9tUWAX}WB3IA4WGhi@Hu<|U&2=eBpAYk zFeL^MHiRwVNVpOjH)0^+Lxd0!L?jVK#1e5t5|K=#5a~oVkwX*_gNZVtoKO%oL_IN* z7)6XG#t>r(4Z#zi5tE3?#1ukHbP+3vZ-~{zI$}Msf!IWBCVnDz6MKmL#LvV5;ym#? zae=rkWx}c`jJ6o2pLYslX5bR%pnWNLb8M`CCkVvvYJ$oO0u3*kKKX!rNIoK;lP@R%1t^LVQU;VEWkgv~E>tiTLWNRcR5%quMN(1JAS!`MrShnJ zs)DMdKBmS~pHQDt6R3&QXVfHWGBt&oN=>7tQ!}WUl$KgZEut1v%c&LAx72D4wT@a( z{XlJ^wo*S)JE>jNK59R8kouMSle$J-r*2R;saw=->JIggdO^LUUQw@Uk~W|XX*1fI zcA(v82`#1lXn#7Kj-Vsy6grhor!(n%dN5r~SJG8|%B^dzih<0p<{Mm^sayVeT^zn1{?G<}vex`I~vlJY$|SFPJwh#Tv1FSYy_L zwPdYWC)SyDVO?2IR?5oQKsJcYU^Ce)Hk-|1bJ;vrlg}2gg=`U9$|~3d~6BiNDb zD0Vc@oH@dxAa5 zo?*|km)Ohf74{GII(v`3&pu!uvrpLP>}w8k1ZTh*azz%4KjlToG5wRde;6ic@nVIiCBN`;42;ea_9{7IGb2C%1%K$*tiw zb6dC{xvktTZa24|`-MBo9pg@N=eYCSMeYgrH}{l##y#g=a4)%6+-vR)_f{wn0wEL< zLQ=>Gz0HJuh5dx)LJOg#&`M}6v=@2`2MWbPiBKw(34?_p!f>Hnm?lgYW(YHdS;AcH zB`OkhY3=D&8)t#5z)j#TuoE~7+;}7W>cboJBA&yajMuHEZGcmm$j;x_&)(0+%icT4 z%ga7Ez}wynzkI#Cg6zEm0s`$>?Oi6>=m&lizm@-q-;RgwS{KVwfL_f@%S2M`4$fj- z4Oa+^-0)l<3&!&U@f^nM4hpkPHFE{xm0%i}4rYLvKnp$xUw|*cEbtYWEf~v>;m7hC zp63z&5kHRqm>3r;TlCnaH>SkL+&6 zz0`OGmPxU3I#TJX#t~WVDitOb-Pl~!&?bV%1xA8C0%Pz!*dh=w0vo{(U=!HPPvR%@ zQ~0Tiz>i=n-t{(q8vi-oa#$dAquzvQd$(P

$qk{RlY1#Nop>IHdZ$MC>zgIWe6W~+_ zILUv>FFys&fZxDbyts4VJop`40J-22xD3D*ZKhql!D9X^UcfKoXYq@)LLY1GB|H11 zKf$d<;2O9NZh)KoY<@ofHQ&K^9S3*7T}3RjnA#&*A6t z^Rj)s0z^#rdLM%)+Nt(-L?`%LJK5ez(>?l`ZZy9@*Eutwm*i^P z>Ki+Cjb);`8fBv*L?)B9v?_;UX~>3Fw90Cl8>HU3EaiFfaVCc8DxTR;6ifl2){|G%BRkYH2|gMo(ONdtO4IOwVpdR*4By4O^U@lU&=4xJ59g2wYjQ7t!!3xK}%>QnEyc!ZJM7e*FCg99H8}g5JPCAt#a@g2<@PK z={v;e_tJ&i@NP~(N9Y8du`o-Z3v`8U+B~yhH~t%bCBI6KALs#YE#$kpKa0Vsh5YjF zDP+(~tLi&|>4M(SM=&3M4$3SOS&SOxCAOD%dyNs>kMarh5!-wF2M3NB)1wy9ABGCV zi(vo^gh4PEhVX0n@A$R+I)43P7$$Io5%?#H-++z4_xNX{_N~K)kffejv0A}Y{b#4B zmMDSlUoY7Vm@N=@!c3UOZ|1jj;;rQ3J^ZNs%Q4TPsAtF!{fKu%N@2M`+yTq@ZQ3DD z5(@>a(^05_wfqi#XD2p#ZaRaf-QX0fX@;Y*#e*$y2yBIIPz~GRP&f<@ha=!fIEvrR z@8S3I`}qC*&-?-Y7ycmsD}RVTyb_LqW1$A}5P^Ac9Q+uLho8Vt;ROB&f0X~7f5tz@ zh zh81IE=o<&MDk_S42I)*;nRBH!#>Gj?xVRdZ$}5H|o0KCJ)q2yVz2|JLmAROEnxP*WgqqTnIb(6Z~0zd2iQ6 zaGAio3oeFB;8Ol1e~Lfd1(yq);WzvlY}|g+-VFEB6k=Q1y*Q^R?frj9Z5`bBui-!7 z;hXt$c=&l$A!GQ0x+fLGz4@EW`hZ}2zyTl{VQ4u6;bi@(R;U#3G0eqoo~{nDWazpzX0 zeyt4~4m2XrOZ7E;+skD_z(3-pdJQ88%x8imDE=}3_d7llEMfRBMr{{36UKPIM*I_A zhFRPAA!`XU!s1^eb_krD32V$CBmSv=NRWPrNN}96BkZwqy#ytMgZ4`oHx2(nujGUi z;XF7kTW{7gD%5qIgo|MQhYdyPEechVDyO2dt!HC|JK-S^FI>n=|KV;3F(DzO*xlq3 z-UtZ!HwYMFUn4*OTP&>DgfFs5x{ywBETTPzH>Q5C=mwkBY?*N z>|+AG{Y6BNmmmhgeY!^kmbUJRZ*O}%k)Ug*5TJE#DacQh(CcmV4y@Z>^)@}jvB~{B z?3O0-^Zrk!p2&xgDAXBl1Prj{hQH`7_i5id!;j&u6cZ&xX;BO2SGKwphXx4rLBOa? z6ri0h4bVn;QvHYuqH=I-UJec_6gs|k5miLBc9VyFu}IL(j#})si8=&K-h-flXcdT; zz&4_ZP!Y{U3o(S>hkz*pW(f2}pdSL}ONcf?O|;|pVFEVvsgE@B!notS}u4FZ`6 zWb<8Th|h^Hh%bp*c)wo}vxzyxTw)$EpIAVAjX!k|o!UybZ=(@#M8FdPF#@&-Waz)* zbq)L{G!_wybUY$1Nsmin1foy1n`vhXL5uG`gg8nZLqLLn6ag6mUI<{k`yk-ElsG}0Bu){hi8I7+#90LV5b#GJ3V}fg zU{1v&kg)E7XA=k^{v>W=CrMl*t`j$io5U>y0uTs9AP9kA1VR=QcZj>hU&K8EGawX! zFa*L8h(I7xJ5{{f;u$!wkk|IA<4fXIw>oO;69TmhB`iq-5^7gU?8PKaGTqO5I+H@u z2s=U2fHXuP27y@YNJ(S<8wBFCHxgpB!BT^0vL9*QJxC8!(h7@)#L!9PyH1ccx^PHf zOxlumq&?|S*rsSyROx~h1X2)4Mj#1+^qHPf+PzZI0MdnY*UjciVo0PSAnznSh`9)) zVX0~#NZm=&i}cpo$Q)?WhxEnbvXR;AMAjYRkp5(V_G_61(Mbks=gX`#NAbLvJ6U?e zMTU}Ld1={c?Tw9{WT;^Nzu-znkdb5*If(e0j3HymI0On1s6?O|fgC+j>k+6xpz0q; zB@@U*9a6~@60f%mfxI51VvvDS95e@O$aJhNWCoc@W+9M|Kp_If??6jNbepIGor%gz zt!P(O)%DmNvWOh4!*dY=gRzyuNrlL~_fdH_)Jy&g)XAD|sB`6dte1&=wDvJR{XPIU zS}b zKoUWu-R5g&sN@AK0(JcJo_XB5c|M-}q)cRv9d>GS?Z2W`@>6nxHpVZ;nw*4P966bs zf?Vr+`4_&%l4%vx7iw?#;F6UpC0-JMeDR|s12wRE|xCWt~YkX&!sDIVFv_Y34 zG&eW4y-O9!M9x}i>;Q+}SiM)DR+Hc9n7jso_6~9_0z-97){x)pn7k2zVVKG9lL&G% z6p=rYTM3Mrkvi9c#W4K;i+tzZy1UaI&HpLi>2YHB^Lm%RgWM@F$F5vf`p?X$S!5%~ z5hw)11!_UNpcQ|zx9=;k|DSCFFWkdd;4Sdc|0wY1DuLHAR+qz)`^f#;xxv<&pLHor zzjrZWqOuLgz9aP6csDS9A!j0>`H!eLgi&#XJc?0qs2dg7kzrI!LV(w!0)PECDo&GU zdQfp5fr*$fdWVY%-6rhIp>UCP%R6_K~eySlM=5cs5n{0o6kd1;XnC(fGg%oziy zH=4&GzBEChQnt6n;Ow>*GebHE!>tKBqpEiv?gQB9a!>Ma2+3#N0m)~&faGAeEd4wz zdKdqae63r+D+DHYkU099qFcOGwifx?XefvQNf8K4{TCo9mg2}~J%F5!z_kDW0qN(w zPL~H@?xrYJ)n(neM9;RUK9t#i3je9TR6n?n!U2#LfzSB|2+ZfDy<@B?yMH7Bf$y>a zoTqhX0TXccX!L%BD<#7z0OdxxQy!EjHINch5=yEqjkI+5e-ZaMkYy294j(5QxC8sj~6~E(%pUTli{0Ly3bc&id{KJr+Dxix0HDm`K zQpR7@=*D#F#*DWA$CxS#dx6y=W2%}`P&HI7RYxhQda8kHq?#xd)l9WeLny3Lix60h zz!C(oSz3m`as*Z&fDP(O1XdyNEdr|%z*g=%1lH=Psi}5iIyDT;6Sz?$@lU{LY78|N zH}MqG1*Yo|*sF^q;W6yfj1fGkdpm{T83eEC+y6%Jsjk`>*$FhCgIg=eInXt%?SL6z)uKlM_?xcyRq87kL;+f9_P2AOyoLTqG)PS zkB}(zX||-dI)h6}s%A-Bd!xTV1?uaT(hr?Rw_)tHi#A(O#>F!NsNKDoS6t)DDad3+i4}wc`IWXO6EU>rD*LX)hmg+)IDrTsd-q_JE;2z9DZ-6A5nkf zgo1iZJwf0I0!KTkrxf;G#}GKqOEozoo12>oTAOhRAFHI3-VWk7z0arK;6gX`mKM-} zh6tQM;1mL<5jfLR`J^fQoTf27{6gTQo+ze!jPG)a>@I3`6QYfDgr0VH)%WV@%WJx8 zsB~X_hwd)DWORLcXX@YcT-T%bIiBg{yEue)q@8sf_zK&-4%!8Qv+p=SyVIWd5sgjN zxeglR@4OC7t{4ib6&h7Fu0`muklkL{EpcfEu9@S23mY&+ief|$hiMt@Eimt(y%6}l zgZ4q-g02u}{m;Jf*cD@PZ8{nCjtiiJ1?HV}ARUCjMFcK&(jfqg=`yzQn1IGoUxCE) z#0_t$z*e)mmqwY$ruR{{qE;6+DXL?dRqEE}Mt$X}mwpr-Coo?GI_YR!qd3J+MBoZe zq^>Wbl3towbdHW;*$7epV|KH9VdY4o}m+6*Nionedx*UO9`lNxb#xWYL zK;ZVjVl=v5SB~n5(eCh_J#qZr)Lx1zxpfu9bo)O_0Q7KrB<@Re zAmG+P<1FibcV7*z(a~dR%|APTMB^G#Cw9oQ^{#hwC;bWiDFP1>zy;0T**~Kv{d3e* zdfGo5X3}5bdIzng7SLbNUs7`rc!E7R0$9_YW4FGTo=r>U&~xc|G~U8X1Z@xuMlct_ zA^((CXOFc0)*43#T6`eJr9BUxm5EZYX?N9LjkdR`tr;$@`%u^`dwRWi-^;b3JNBnn z)0?sVr`OQm(QD~-^m=*&{XM;r{(;_v0FJ3&BYN;GfZy;!hpiw7%i@uFu z9|VoH#z8g_-D+}Qf6QajpXe3aWBM5mC+R2j-}F-iO%OCi(5#DoPQReB2>K#uj-UlE z(@xJCsO_7c#WFx(%s__Fs?r@iU_X6HfT0)~mtl0rT%8OhnC}!-y-;s=k1-tXEyTU& zq&oz`eoj%A-S$}YW6%7IF=L9C&4?I0b$d3Rmu?f%vajpuB@&c zp;ok|i$t8?qs@PxmyiB5cJIPrn(FTn<~mb>`&RzD@8IvNqt>)1Xg?ih=iwjZh$Y&u zm(dEQPPfh)`Z|Js7$TjFlD>tYKZXd-{HvR*w2j%8{acu}ZgI5g#Sw(X!6@}8^4ETy zZB;#j`B*20k<2J&G&6=7%V-#$LCiJvb)7FS0{#f2*&k_;p_h@h9%5$-NKhL%MeUJFtL+a z!F+>Y5`wAPExF14*D&kwbNV{7R<9n(x{YnnZ!AS?pJ(f~nfXa4rY+2m%vJ>D2&N&J z-oV%s>#QG3I(b7_8l%=fv#80@#m%eJjtwKqru2@b`oGyLrBYJM3qY(RB?y)xShj-svxlQMF-LD>j^5RAw7i$2m3oet0>iPMZj-QjdO*lIk zGnB;=8Pmg1w(P$$w1!pc_*Ki+A*ex+?_}%Q23%}K@KbCllHA!AR;}aL5Vn=Y%lrsI ztW+O&VQvj&@lvrN9*^KB7=zpM9I!nu*05tRm&X3v3Vc4+VEHVkl=j&^7avTRyl1=4 zVz3DJ{pjC)FV8*|d+~N`)xy-Vf}aogB)_*9?09y9ZoQxAx85mh6n3}q+w^X_;OJPH4CTp9V}Mzsqf+l z_G@@s$RqVIyYIY5RGZ4h{Y7zV#!7mW} z62VzZ*|qFCc0Id+{hr;(n*V^{R|w8Va1nxw5yV8XsaV;4EW_?%f5u@7yPMs^?q&C} z`w^Uj;9LapGUp?>U@?1u{e?Zq{>mOg@M{DYBG`doCxTu0SjI=YI(~)|d+Nip8TL2! z>_2z(J9|M}l~5pIud=w*s5?aMW!w!G9|?7`H(AW*r3fzTWbd$d5nPVo3Vbw^s9_)K z{de}D#>UDTS zK78QS^I(hir+<#{?|HCQJ1;5BlndfQFz`4WgKq2KLJ{1qkI*?B4s>wXv+ei~XD6Hk zmw-v7R z8+EJgj)FM_SNonAHda6P5^DgrG#wl^+z0*xHL?bqvhKZua{hTQv373QJ7UlU7hHS6 z&W+;6ynDi7^ZIM=G&mXR;IR2S^dDx?a9-~hz2$>NPvWM$r#2PABfZpS=%`_XaP&V= zxs4pwn)3)=Lhujm z?6OH3?k8@$Zcp0~{Jn$Qf#3zKiQR|b$GANhG<&&yI?(9upkaMZZ%7!o9h;+z-O%}& zJJ1ahMJI=kUwY+nkUONK`745#JGjFLUU^Rw1GNm4b0_$wGLhKJOWRfM-IqJXoze9_ zjo{S|4zKo4UaDPCF4J_c;CF6c_sq+OufsFe2Cy9 z1Ro>#1UqC|k#gOa6$FS7Qb2cAt!G*xE5rxei-ep|C^QfnBKQo!=Lo()@Z}<5AEB{O zBs4+r6@sr3e1qUy?di%dV}$*|sV?CFp^eZM5duWeh~VB+bP&4W>k~ppp_9-V5daYo z5k!~JRp=({g9s846eg%$Q#C6{=q2>~4_#?m7$6MP)shGX5iBpQ64<*yfxTYqg`r&f zx(U@HG8OLb-9v;h4x3dxW0Y`^&{-HGjMdL8M1%pJ8WDzwFj^vvhx>$y!X*7I4x$e} z`5=rDA=2IEz~V7fI%rwtry3nbgxPutWy73>W=>c_B{|L26(j5`)b>GAzaRlCuo5^5 z#Q5YcL=Y*+6yynt1*P=I^k?)ee2;wv&V#?l+3#kY*6yHp)I{cIBo{F z0ISUgtSX!E#q6!zHf{&Ln!ShHhc9Gb;4WdfUBytl!QJBSaDQnqjvivcWeBT<6NPhy zJA@Yvpn-!yq(Q1dzCoeEV1p8aGJ^_(Mgx^Wi$SY_+F+=`aD&eb)*GBRxNQgxjSWo= z`x;spS{e2?lo*B>h8l($Mi?d-W*H7P9AY@!aJ=DE!&!#&3^y3=G~8pj&+vfZLBm6a z=M2vq{%&~D@Q$J8iQ!Yj=Y}s0UmMXztdY>j(5R1*$jHqo)F{WO*=V%U7^AWHTK8O| zWk%l^tuk6;wAN_7(P5)AMo)~M8a?mxZJ&*OF7>%?EHZ94{>XTe@f71}#xrm(KhJo9 z@j~NH<3+|xjJFyeHNGXHMD`+y$V=oS@)re)f<-x^646M}XpLyBiLXhNNv27*Nv=u0 zNukMLlM<6MlM0ho6Sc`uli?;KO-7rHHQ`M@GWpo#Ta#lZPfTr0qf8a16HK?8{%U&4 z^o;3Q)AObmOs|{XG`($l*Yuw012fiafSJEphFOVOxml%|!mQRzY4&lygZ-}ed))77 zzvum4^?PG3Fz;{fY_1t(9%CM7{=$N>5Ly^o7+aWFm{~|I0xfbZ@+=B0jV!G#Z7l69 z9W9+LT`i+6(=GEX3oMH)i!G}x6_&M@O3Mbz&n&;T{Kj&ZWc(t40}jCGuKv2}~}MC(P?+pG^-AGSVfeZu;b^%?6&*01_o z_3z)`#%7Dnew)iSf7twKbKT~q&25{zHur2E*gUd%V)NAIxvi;fUt4oqOIvH(0k*cb z_O_0;&bF?$?zWz`V%un2O}_0A+iAATZMWH;wS8>Y*Ur^$kX?*jhFziEV7n5#GP?@9 zdb>tDm0gQntDV|zvfWy{Yxa!2$lk)<%D%t7jlG?{i~T@*Z~GAY1p74m9Q#uHTKjtY zMthb0r}lH~m)q~KKVg60{-OP2`@ij<*}t%V<>2KI>=5k`>k#jd=#Z>&NOdT5sCKA# zXmn6Hv^c08hB{~*7C3Y{>~uKnaMamA!1 zM>+D26CD>gE_M9QajWBD$D@wN9Zx!*c0B9&hvOY5#;K2!hf}0eqEnmGaHlS(l}=ln zb~+t*y5#iC+0eO$52-tD~C zdB5`k=abH-oquya=lr|#Md!;dw2PxlkV~mcyUSFUSuS6>%yH>*S>&?BWwpzXE<0Ry zx$JQ{;BwIAkjoL57p}IhZm#aGp02*GQLZtrajuE3$*!rc^{&HQN4t)7vPwauCHC+x&b%BZGfAto4uQ(o3op%o4cE* zo7he2=I!R^7U&l2R_xZ|HpXp&+c$1!+-|uWx%;|DyBE2)xQ}HdZLEcZF?^V}D> zuXW$zzTJJN`)>EW?#JEFx}SHy;C{(nbKU)>`)&8T?)ThZdk8&jJls6IJioqQ zJ(4{#J+eJ=J@P#YJsLdJ9?0V}kI5cWJ*Ioi^qA{0-{WhK4v#L6#U9^!{NS<6TxAs!{3Af6_kA=Zk&5YH1Y5HA#WiWiAji8qUPh zY9Y0fI!Xhj!O~D^gfvPTBTbd&O3S5H(i-X4(q+>1(k;?`(%+=#q*pc4>(X1&JJRPe zTE@x@WPM~Nvc574nX}AI<|&iNykx#Ie_5a`MOGnemW`6lmCcu}kbNgxFWV^FEZZU5 zE!!*GFFPQ+D0}EddKr23^|J7?_OkJ^^NR8+_Ts%}dad!=?RCWKFRuq)kG-CHz3_VN zE$}A1X>U7kM{gHzjk~v}H@+k9UFqH6t@0k?-R8}EkMkby{i*jL z2Kt8hhWkeO#`wnjCi$lNrumNbUFmzy&%iIvuhDO=-&((Ieg`yuzxo~VJMMSN?>E1z ze%JkO`Q7!q@At^>iNBM7vVWWZm;T@RZ}#8fzt#VM|1bUr{SO6D0d#;_K;M9V0TuzC z0f7NQ0l@*G0f_<-u)a5~^} zz}0~30k;C~21)`00%HO-iGeABX@S{+d4Yw2g99rAm4TxJ#|JJBTp4&U@JitAAQ;31 z*#Yyn>(}T1@Uj}^@G&g8L(6OL%L05wQ z47w3?JLqoEi=fv*Z-YTF8{9A0GPr-RO|V0-Q?OUCZ!rE-gy4wa1Wj;GaDH%6aB=XA z;03`8gS)pgZRG=vOcLWChkA)*k|5NSwYNJvO{NMuM(NNvcF5Ov7VkYOPsLq>;u z7qU6zc*xn1N1u`_on(*fEPs1mNFA853z9xKK_=)h- z;b+5t55E-tNBFhyo8fmNs0cQ~Afiu%D8e+NUxaOhQ-o`TN5sI0pomaSL`1}(h}eku zh`|xH5$cFx5hEkUMDP(GMNElUAF(y!Sj35lQxU&KoQt>+aXsR3#M6iu5w9Z!kucIW z(k;?6QW7bPjEzi)Oo~j6Opn|gxhwKyMG zj5CT8#hJyK$63V$#%)^$==B! z$>GUS$uY_C$%)CC$wkQ}$>qsa$u-G!$wQJyCXY-0Bza=;~+_eJLkWeowiWawX+z%C(exDGyVgq&!P` znesa2Z7Q3}r5dL8OSMjQOZ7~Zqu@`l=qRF$j#&f1ygX5!D=&}_mg7I9kypuE zuW3D9tP_DJ?IpAZ>73Y1+!PO=(-weoEVsZk#?K-86-L;>08n-W`GQr zjFgP#jHwx`G7e-M&p4IwTgJJJs~LAQ?qxj4c$D!Z<7pX58fW&^WLjieXAZ~= z&MeMUW~wrWWU4bqWRA|%WTMO|ne#FiXD-QHmibNQ51HFCcV_O%+@EBvSwz@%37GUJnQ?cpR*2ToyhrtIeI*6jA|;n^dz$7E}= zQTBrDt=X4zh#a>ZdCriW={c)&4(6Q9Ig@iP=l7gzIrnlN|Jkvb8JReP-e_ljh zN?vJRMV>0JEpKSvh`h0RDDUIEPx8LV`zmiv-qO64d8_l*=55T|oVPV^Ti&6(b9wjk z9_9U=_dM@a-rIbbPvx`u2KjyRo$_7t-Sa*3#rd*)pM3xP!2FQ>u>6Sp!TBTe7vyix zzgi$HkQT@b8Ve>C%q;k#;H!c;1)8pcl?C4xtSMMqu)g5?f?Wms3w|j$RB*iDRKafr z=L((`_AhiVloWau`W6Nih89K?Mir(P<`h;G))h7sstSh`4lf*4IJOWKjw@VQc%krZ z5nI%+$h~M_kzdiEqMV}qqN1YOqQ;`;qSm5eMI(#G6lsd47R@bMQ?#z=`=U)nKWd7$ z740nAQ?$S6m!d;Oe-vFSx>0ni=uXkSqK8FKik=p|D0)@&W^n((A%jZ?^Me-+J}~&N zVxwYlaZ+(sac*%zaZzzqabvNnxTUzYSY14{cwF&>;z`9*i?zjH7SAr8Tl_=ux#Ane zcZ=^AKPrA!{Id8>iJ-)|#I(e&#I?kuL|megl?0RomxPr>mJBLsEBU-+Ysub{<0aQh zZk9YOd0T2)+OO2I)TPw3R8s0y>R%dE8d@4&np#>|swy2)sxBQ?I2Iaa$_A80lvS2ZC|gZY zE#F?gt9)j@rWLUj@`|F0rizw|5fz_Q%&wSMvAp8jitj4cS8S^Iv0_`rj*24{ z$16@&T&cKTajW8P#lwmx70)VORC1N(l~$DlD(xyYj+M@p-jzO;zLox!(UozPiIpjp zX_Xn3C6$ep&6TZ{?UlnTM^%okM3vJkwUu91&aRwS`E_My<>Jbvm8YwyD!;1gss&Yh zsvcJxR9jX%Rl8PuREw)+)jrkX)lt`Sv6%f)it#>^)<~ktu^g6!)nIXjIa5s zW^v8hnhiBS)NHBwsb)vb?wX@DCu&aDoUQr2Msum=kD5Pg9@adrd0O+LR#qEU8&Nx` zHnw&|?I*PpYA4lBtvyzIvG#K9)!OTI1L{2L2G&XIyz6S}+UkbZji?)4r>R4A^Xrz> zEw5Wy_if#-y1jM#>wc~~Sa-PYeBEDl59%J(y;71&Mk!R9DIJvVN|`cD8L5m`#win( z$;xbvGEZ5k9IR|nwkg|{LzN?xqm>htlaaSRv%U$Ssz^= zSD#p)T%TQ^S6^5^xW1*nt-if}X#I%#(e;{%^^@zT)z7T|qJCEW;`){K8|r_k-(3G= z{m=CW>kri*tv^wJs{UgAmHMmo*XkeDzo>uRAZQ>OgbhXwq6V{uehmQ)s)kt&iyD?T ztY}!(u%=;c!={Fv4F?*IH=Js?*l?}kcEhuVmknZ7tyS*om6ZYnR8uPQ(l ztO`@bsS;Hwsx(!mDqGd4`c&1aI;lFRx}?%vQQcNOR6S8WQ@vEZZWcD1H1}<`Xtr*4 zXm)OPYxZmwH|I8wYhK;_L-Xe5ea(lOk2arZKHYqw`Ev8s=IhNjo9{P2SF>sZwWZoc z?XDiEma4tge(FGVtU5uRq)t_*t25Qv>Rk0m_1Eg3)sNJ#+Nt(F?Izth)xBGtpP-s_Z delta 14770 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 F{|CNb@FoBN