diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index da7e671b..21a2142b 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -642,6 +642,10 @@ namespace Nuake { { texture = Engine::GetCurrentScene()->m_SceneRenderer->GetGBuffer().GetTexture(GL_COLOR_ATTACHMENT6); } + else if (SelectedViewport == 6) + { + texture = Engine::GetCurrentScene()->GetEnvironment()->mSSAO->GetOuput()->GetTexture(); + } ImVec2 imagePos = ImGui::GetWindowPos() + ImGui::GetCursorPos(); Input::SetEditorViewportSize(m_ViewportPos, viewportPanelSize); @@ -1964,7 +1968,7 @@ namespace Nuake { ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(20, 20, 20, 0)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, IM_COL32(20, 20, 20, 60)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, IM_COL32(33, 33, 33, 45)); - const char* items[] = { "Shaded", "Albedo", "Normal", "Depth", "Velocity", "UV"}; + const char* items[] = { "Shaded", "Albedo", "Normal", "Depth", "Velocity", "UV", "SSAO"}; ImGui::SetNextItemWidth(128); if (ImGui::BeginCombo("##Output", items[SelectedViewport])) { @@ -2496,6 +2500,14 @@ namespace Nuake { } } +#ifdef NK_DEBUG + // Shader reloading + if (ImGui::IsKeyPressed(ImGuiKey_F1, false)) + { + ShaderManager::RebuildShaders(); + } +#endif + pInterface.m_CurrentProject = Engine::GetProject(); uint32_t selectedEntityID; diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 4e33df77..721b9b99 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -912,7 +912,7 @@ void EditorSelectionPanel::DrawFile(Ref file) ImGui::Text("SSAO Strength"); ImGui::TableNextColumn(); - ImGui::DragFloat("##SSAOStrength", &env->mSSAO->Strength, 0.1f, 0.0f, 10.0f); + ImGui::DragFloat("##SSAOStrength", &env->mSSAO->Strength, 0.01f, 0.01f, 10.0f); ImGui::TableNextColumn(); // Reset button @@ -928,13 +928,13 @@ void EditorSelectionPanel::DrawFile(Ref file) ImGui::Text("SSAO Radius"); ImGui::TableNextColumn(); - ImGui::DragFloat("##SSAORadius", &env->mSSAO->Radius, 0.001f, 0.0f, 1.0f); + ImGui::DragFloat("##SSAORadius", &env->mSSAO->Radius, 0.01f, 0.0f, 10.0f); ImGui::TableNextColumn(); // Reset button ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); std::string resetRadius = ICON_FA_UNDO + std::string("##resetRadius"); - if (ImGui::Button(resetRadius.c_str())) env->mSSAO->Radius = 0.5f; + if (ImGui::Button(resetRadius.c_str())) env->mSSAO->Radius = 1.0f; ImGui::PopStyleColor(); } @@ -944,45 +944,13 @@ void EditorSelectionPanel::DrawFile(Ref file) ImGui::Text("SSAO Bias"); ImGui::TableNextColumn(); - ImGui::DragFloat("##SSAOBias", &env->mSSAO->Bias, 0.0001f, 0.0f, 0.5f); + ImGui::DragFloat("##SSAOBias", &env->mSSAO->Bias, 0.0001f, 0.00001f, 0.5f); ImGui::TableNextColumn(); // Reset button ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetSSAOBias"); - if (ImGui::Button(resetBloomThreshold.c_str())) env->mSSAO->Bias = 0.025f; - ImGui::PopStyleColor(); - } - - ImGui::TableNextColumn(); - { - // Title - ImGui::Text("SSAO Area"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##SSAOArea", &env->mSSAO->Area, 0.0001f, 0.0f, 0.5f); - ImGui::TableNextColumn(); - - // Reset button - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetSSAOArea"); - if (ImGui::Button(resetBloomThreshold.c_str())) env->mSSAO->Area = 0.0075f; - ImGui::PopStyleColor(); - } - - ImGui::TableNextColumn(); - { - // Title - ImGui::Text("SSAO Falloff"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##SSAOFalloff", &env->mSSAO->Falloff, 0.0001f, 0.0f, 0.5f); - ImGui::TableNextColumn(); - - // Reset button - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetSSAOFalloff"); - if (ImGui::Button(resetBloomThreshold.c_str())) env->mSSAO->Falloff = 0.0022f; + if (ImGui::Button(resetBloomThreshold.c_str())) env->mSSAO->Bias = 0.001f; ImGui::PopStyleColor(); } diff --git a/Nuake/src/Rendering/PostFX/SSAO.cpp b/Nuake/src/Rendering/PostFX/SSAO.cpp index 7a894b6a..784fda74 100644 --- a/Nuake/src/Rendering/PostFX/SSAO.cpp +++ b/Nuake/src/Rendering/PostFX/SSAO.cpp @@ -22,12 +22,12 @@ namespace Nuake _ssaoFramebuffer = CreateRef(false, Vector2(_size)); - auto renderTarget = CreateRef(_size, GL_RGBA, GL_RGBA16F, GL_FLOAT); + auto renderTarget = CreateRef(_size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); _ssaoFramebuffer->SetTexture(renderTarget, GL_COLOR_ATTACHMENT0); _ssaoBlurFramebuffer = CreateRef(false, Vector2(_size)); - auto renderTargetBlur = CreateRef(_size, GL_RGBA, GL_RGBA16F, GL_FLOAT); + auto renderTargetBlur = CreateRef(_size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); _ssaoBlurFramebuffer->SetTexture(renderTargetBlur); } @@ -92,7 +92,7 @@ namespace Nuake _ssaoNoise.push_back(noise); } - _ssaoNoiseTexture = CreateRef(Vector2(4, 4), GL_RGB, GL_RGBA16F, GL_FLOAT, &_ssaoNoise[0]); + _ssaoNoiseTexture = CreateRef(Vector2(4, 4), GL_RGB, GL_RGB16F, GL_FLOAT, &_ssaoNoise[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); @@ -106,8 +106,13 @@ namespace Nuake _ssaoFramebuffer->Bind(); { _ssaoFramebuffer->Clear(); - const auto& depthTexture = gBuffer->GetTexture(GL_DEPTH_ATTACHMENT); - const auto& normalTexture = gBuffer->GetTexture(GL_COLOR_ATTACHMENT1); + auto depthTexture = gBuffer->GetTexture(GL_DEPTH_ATTACHMENT); + auto normalTexture = gBuffer->GetTexture(GL_COLOR_ATTACHMENT1); + + ImGui::Begin("debug"); + ImGui::Image((ImTextureID)normalTexture->GetID(), ImGui::GetContentRegionAvail(), { 0, 1 }, { 1, 0 }); + ImGui::End(); + Shader* shader = ShaderManager::GetShader("Resources/Shaders/ssao.shader"); shader->Bind(); shader->SetUniform("u_Projection", projection); diff --git a/Nuake/src/Rendering/PostFX/SSR.cpp b/Nuake/src/Rendering/PostFX/SSR.cpp index 5f0f96d8..bc0edd37 100644 --- a/Nuake/src/Rendering/PostFX/SSR.cpp +++ b/Nuake/src/Rendering/PostFX/SSR.cpp @@ -8,7 +8,6 @@ namespace Nuake { SSR::SSR() { mSize = Vector2(1280, 720); - mShader = ShaderManager::GetShader("Resources/Shaders/ssr.shader"); } void SSR::Init() @@ -32,7 +31,7 @@ namespace Nuake { OutputFramebuffer->Bind(); { RenderCommand::Clear(); - + mShader = ShaderManager::GetShader("Resources/Shaders/ssr.shader"); mShader->Bind(); mShader->SetUniform("rayStep", RayStep); diff --git a/Nuake/src/Rendering/Shaders/Shader.cpp b/Nuake/src/Rendering/Shaders/Shader.cpp index 2133414a..714ffa20 100644 --- a/Nuake/src/Rendering/Shaders/Shader.cpp +++ b/Nuake/src/Rendering/Shaders/Shader.cpp @@ -44,12 +44,14 @@ namespace Nuake return false; } - ShaderSource newSource = ParseShader(FileSystem::ReadFile(this->Path)); + ShaderSource newSource = ParseShader(FileSystem::ReadFile(this->Path, true)); unsigned int newProgramId = CreateProgram(newSource); if(newProgramId == 0) return false; + UniformCache.clear(); + Source = newSource; programId = newProgramId; diff --git a/Nuake/src/Rendering/Shaders/ShaderManager.cpp b/Nuake/src/Rendering/Shaders/ShaderManager.cpp index 5529bbc6..bbbaa754 100644 --- a/Nuake/src/Rendering/Shaders/ShaderManager.cpp +++ b/Nuake/src/Rendering/Shaders/ShaderManager.cpp @@ -5,7 +5,7 @@ #include #define LoadEmbeddedShader(file) \ -m_Shaders[file##_path] = CreateScope(file##_path, std::string(reinterpret_cast(file), reinterpret_cast(file) + file##_len)); +m_Shaders[file##_path] = CreateScope("../" + file##_path, std::string(reinterpret_cast(file), reinterpret_cast(file) + file##_len)); namespace Nuake { diff --git a/Nuake/src/Resource/StaticResources.cpp b/Nuake/src/Resource/StaticResources.cpp index 1e5e6e4e..c60b84a2 100644 --- a/Nuake/src/Resource/StaticResources.cpp +++ b/Nuake/src/Resource/StaticResources.cpp @@ -274245,10 +274245,10 @@ namespace Nuake { 0x65, 0x6E, 0x74, 0x0D, 0x0A, 0x23, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x34, 0x34, 0x30, 0x20, 0x63, 0x6F, 0x72, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, 0x75, 0x6E, 0x69, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x73, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x32, 0x44, 0x20, 0x75, 0x5F, 0x44, 0x65, - 0x70, 0x74, 0x68, 0x3B, 0x0D, 0x0A, 0x75, 0x6E, 0x69, 0x66, 0x6F, 0x72, - 0x6D, 0x20, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x32, 0x44, 0x20, - 0x75, 0x5F, 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x3B, 0x0D, 0x0A, 0x75, + 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x32, 0x44, 0x20, 0x75, 0x5F, 0x4E, 0x6F, + 0x72, 0x6D, 0x61, 0x6C, 0x3B, 0x0D, 0x0A, 0x75, 0x6E, 0x69, 0x66, 0x6F, + 0x72, 0x6D, 0x20, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x32, 0x44, + 0x20, 0x75, 0x5F, 0x44, 0x65, 0x70, 0x74, 0x68, 0x3B, 0x0D, 0x0A, 0x75, 0x6E, 0x69, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x32, 0x44, 0x20, 0x75, 0x5F, 0x4E, 0x6F, 0x69, 0x73, 0x65, 0x3B, 0x0D, 0x0A, 0x75, 0x6E, 0x69, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x69, @@ -274291,10 +274291,12 @@ namespace Nuake { 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x7A, 0x4E, 0x65, 0x61, 0x72, 0x2C, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x7A, 0x46, 0x61, 0x72, 0x29, 0x0D, 0x0A, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, - 0x75, 0x72, 0x6E, 0x20, 0x7A, 0x4E, 0x65, 0x61, 0x72, 0x20, 0x2A, 0x20, - 0x7A, 0x46, 0x61, 0x72, 0x20, 0x2F, 0x20, 0x28, 0x7A, 0x46, 0x61, 0x72, - 0x20, 0x2B, 0x20, 0x64, 0x20, 0x2A, 0x20, 0x28, 0x7A, 0x4E, 0x65, 0x61, - 0x72, 0x20, 0x2D, 0x20, 0x7A, 0x46, 0x61, 0x72, 0x29, 0x29, 0x3B, 0x0D, + 0x75, 0x72, 0x6E, 0x20, 0x28, 0x32, 0x2E, 0x30, 0x20, 0x2A, 0x20, 0x7A, + 0x4E, 0x65, 0x61, 0x72, 0x20, 0x2A, 0x20, 0x7A, 0x46, 0x61, 0x72, 0x29, + 0x20, 0x2F, 0x20, 0x28, 0x7A, 0x46, 0x61, 0x72, 0x20, 0x2B, 0x20, 0x7A, + 0x4E, 0x65, 0x61, 0x72, 0x20, 0x2D, 0x20, 0x64, 0x20, 0x2A, 0x20, 0x28, + 0x7A, 0x46, 0x61, 0x72, 0x20, 0x2D, 0x20, 0x7A, 0x4E, 0x65, 0x61, 0x72, + 0x29, 0x29, 0x20, 0x2F, 0x20, 0x34, 0x30, 0x30, 0x2E, 0x30, 0x3B, 0x0D, 0x0A, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x76, 0x65, 0x63, 0x33, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x50, 0x6F, 0x73, 0x46, 0x72, 0x6F, 0x6D, 0x44, 0x65, 0x70, 0x74, 0x68, 0x28, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x64, @@ -274319,241 +274321,157 @@ namespace Nuake { 0x63, 0x65, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x2F, 0x3D, 0x20, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x77, 0x3B, 0x0D, 0x0A, - 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x77, - 0x6F, 0x72, 0x6C, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6F, 0x73, - 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x3D, 0x20, 0x76, 0x5F, 0x49, 0x6E, - 0x76, 0x56, 0x69, 0x65, 0x77, 0x20, 0x2A, 0x20, 0x76, 0x69, 0x65, 0x77, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, - 0x6E, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, - 0x74, 0x75, 0x72, 0x6E, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x53, 0x70, - 0x61, 0x63, 0x65, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x2E, - 0x78, 0x79, 0x7A, 0x3B, 0x0D, 0x0A, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x76, - 0x65, 0x63, 0x33, 0x20, 0x56, 0x69, 0x65, 0x77, 0x50, 0x6F, 0x73, 0x46, - 0x72, 0x6F, 0x6D, 0x44, 0x65, 0x70, 0x74, 0x68, 0x28, 0x66, 0x6C, 0x6F, - 0x61, 0x74, 0x20, 0x64, 0x65, 0x70, 0x74, 0x68, 0x29, 0x0D, 0x0A, 0x7B, - 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, - 0x7A, 0x20, 0x3D, 0x20, 0x64, 0x65, 0x70, 0x74, 0x68, 0x20, 0x2A, 0x20, - 0x32, 0x2E, 0x30, 0x20, 0x2D, 0x20, 0x31, 0x2E, 0x30, 0x3B, 0x0D, 0x0A, - 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x63, - 0x6C, 0x69, 0x70, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6F, 0x73, 0x69, - 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x34, 0x28, - 0x55, 0x56, 0x20, 0x2A, 0x20, 0x32, 0x2E, 0x30, 0x20, 0x2D, 0x20, 0x31, - 0x2E, 0x30, 0x2C, 0x20, 0x7A, 0x2C, 0x20, 0x31, 0x2E, 0x30, 0x29, 0x3B, - 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, - 0x69, 0x65, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6F, 0x73, 0x69, - 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x3D, 0x20, 0x76, 0x5F, 0x49, 0x6E, 0x76, - 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x2A, - 0x20, 0x63, 0x6C, 0x69, 0x70, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6F, - 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6F, - 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x78, 0x79, 0x7A, 0x20, 0x2F, - 0x3D, 0x20, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, - 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x77, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70, 0x61, 0x63, 0x65, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x78, 0x79, 0x7A, 0x3B, 0x0D, - 0x0A, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x76, 0x65, 0x63, 0x33, 0x20, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x5F, 0x66, 0x72, 0x6F, 0x6D, 0x5F, 0x64, - 0x65, 0x70, 0x74, 0x68, 0x28, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x64, - 0x65, 0x70, 0x74, 0x68, 0x2C, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, - 0x65, 0x78, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x73, 0x29, 0x20, 0x7B, 0x0D, - 0x0A, 0x20, 0x20, 0x0D, 0x0A, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, - 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x31, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x30, 0x2E, 0x30, - 0x2C, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x32, 0x29, 0x3B, 0x0D, 0x0A, 0x20, - 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, - 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x32, 0x20, 0x3D, 0x20, 0x76, 0x65, - 0x63, 0x32, 0x28, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x32, 0x2C, 0x30, 0x2E, - 0x30, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x0D, 0x0A, 0x20, 0x20, 0x66, - 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x64, 0x65, 0x70, 0x74, 0x68, 0x31, 0x20, - 0x3D, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, - 0x44, 0x65, 0x70, 0x74, 0x68, 0x2C, 0x20, 0x55, 0x56, 0x20, 0x2B, 0x20, - 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x31, 0x29, 0x2E, 0x72, 0x3B, 0x0D, - 0x0A, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x64, 0x65, 0x70, - 0x74, 0x68, 0x32, 0x20, 0x3D, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, + 0x0A, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x76, 0x6F, 0x69, 0x64, + 0x20, 0x6D, 0x61, 0x69, 0x6E, 0x28, 0x29, 0x0D, 0x0A, 0x7B, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x64, 0x65, + 0x70, 0x74, 0x68, 0x20, 0x3D, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, 0x44, 0x65, 0x70, 0x74, 0x68, 0x2C, 0x20, 0x55, - 0x56, 0x20, 0x2B, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x32, 0x29, - 0x2E, 0x72, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x0D, 0x0A, 0x20, 0x20, 0x76, - 0x65, 0x63, 0x33, 0x20, 0x70, 0x31, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, - 0x33, 0x28, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x31, 0x2C, 0x20, 0x64, - 0x65, 0x70, 0x74, 0x68, 0x31, 0x20, 0x2D, 0x20, 0x64, 0x65, 0x70, 0x74, - 0x68, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, - 0x70, 0x32, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x33, 0x28, 0x6F, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x32, 0x2C, 0x20, 0x64, 0x65, 0x70, 0x74, 0x68, - 0x32, 0x20, 0x2D, 0x20, 0x64, 0x65, 0x70, 0x74, 0x68, 0x29, 0x3B, 0x0D, - 0x0A, 0x20, 0x20, 0x0D, 0x0A, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, - 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x63, 0x72, 0x6F, - 0x73, 0x73, 0x28, 0x70, 0x31, 0x2C, 0x20, 0x70, 0x32, 0x29, 0x3B, 0x0D, - 0x0A, 0x20, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x2E, 0x7A, 0x20, - 0x3D, 0x20, 0x2D, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x2E, 0x7A, 0x3B, - 0x0D, 0x0A, 0x20, 0x20, 0x0D, 0x0A, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, - 0x72, 0x6E, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x65, - 0x28, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x29, 0x3B, 0x0D, 0x0A, 0x7D, - 0x0D, 0x0A, 0x0D, 0x0A, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x6D, 0x61, 0x69, - 0x6E, 0x28, 0x29, 0x0D, 0x0A, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x64, 0x65, 0x70, 0x74, 0x68, 0x20, - 0x3D, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, - 0x44, 0x65, 0x70, 0x74, 0x68, 0x2C, 0x20, 0x55, 0x56, 0x29, 0x2E, 0x72, - 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x64, - 0x65, 0x70, 0x74, 0x68, 0x20, 0x3E, 0x20, 0x30, 0x2E, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x66, 0x29, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, - 0x72, 0x61, 0x67, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x76, - 0x65, 0x63, 0x34, 0x28, 0x30, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x30, 0x2C, - 0x20, 0x30, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x0D, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, - 0x53, 0x43, 0x41, 0x4C, 0x49, 0x4E, 0x47, 0x5F, 0x4E, 0x45, 0x41, 0x52, - 0x20, 0x3D, 0x20, 0x30, 0x2E, 0x39, 0x32, 0x3B, 0x0D, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x64, 0x65, 0x70, 0x74, - 0x68, 0x53, 0x63, 0x61, 0x6C, 0x65, 0x72, 0x20, 0x3D, 0x20, 0x28, 0x64, - 0x65, 0x70, 0x74, 0x68, 0x20, 0x2D, 0x20, 0x53, 0x43, 0x41, 0x4C, 0x49, - 0x4E, 0x47, 0x5F, 0x4E, 0x45, 0x41, 0x52, 0x29, 0x20, 0x2F, 0x20, 0x28, - 0x31, 0x2E, 0x30, 0x20, 0x2D, 0x20, 0x53, 0x43, 0x41, 0x4C, 0x49, 0x4E, - 0x47, 0x5F, 0x4E, 0x45, 0x41, 0x52, 0x29, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x66, 0x6C, - 0x6F, 0x61, 0x74, 0x20, 0x6D, 0x69, 0x6E, 0x52, 0x61, 0x64, 0x69, 0x75, - 0x73, 0x20, 0x3D, 0x20, 0x30, 0x2E, 0x30, 0x35, 0x66, 0x3B, 0x0D, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x66, 0x6C, - 0x6F, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x78, 0x52, 0x61, 0x64, 0x69, 0x75, - 0x73, 0x20, 0x3D, 0x20, 0x31, 0x2E, 0x32, 0x66, 0x3B, 0x0D, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x20, 0x66, 0x6C, 0x6F, - 0x61, 0x74, 0x20, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x72, 0x50, 0x6F, 0x77, - 0x20, 0x3D, 0x20, 0x31, 0x2E, 0x38, 0x66, 0x3B, 0x0D, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x64, 0x65, 0x70, 0x74, 0x68, 0x53, 0x63, 0x61, 0x6C, 0x65, - 0x72, 0x20, 0x3D, 0x20, 0x6D, 0x69, 0x6E, 0x28, 0x6D, 0x61, 0x78, 0x28, - 0x70, 0x6F, 0x77, 0x28, 0x64, 0x65, 0x70, 0x74, 0x68, 0x53, 0x63, 0x61, - 0x6C, 0x65, 0x72, 0x2C, 0x20, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x72, 0x50, - 0x6F, 0x77, 0x29, 0x2C, 0x20, 0x6D, 0x69, 0x6E, 0x52, 0x61, 0x64, 0x69, - 0x75, 0x73, 0x29, 0x2C, 0x20, 0x6D, 0x61, 0x78, 0x52, 0x61, 0x64, 0x69, - 0x75, 0x73, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6C, - 0x6F, 0x61, 0x74, 0x20, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x64, 0x52, 0x61, - 0x64, 0x69, 0x75, 0x73, 0x20, 0x3D, 0x20, 0x75, 0x5F, 0x52, 0x61, 0x64, - 0x69, 0x75, 0x73, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x76, 0x65, 0x63, 0x33, 0x20, 0x66, 0x72, 0x61, 0x67, 0x50, 0x6F, 0x73, - 0x20, 0x3D, 0x20, 0x56, 0x69, 0x65, 0x77, 0x50, 0x6F, 0x73, 0x46, 0x72, - 0x6F, 0x6D, 0x44, 0x65, 0x70, 0x74, 0x68, 0x28, 0x64, 0x65, 0x70, 0x74, - 0x68, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, - 0x33, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x74, - 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, 0x4E, 0x6F, 0x72, - 0x6D, 0x61, 0x6C, 0x2C, 0x20, 0x55, 0x56, 0x29, 0x2E, 0x78, 0x79, 0x7A, - 0x20, 0x2A, 0x20, 0x32, 0x2E, 0x30, 0x20, 0x2D, 0x20, 0x31, 0x2E, 0x30, - 0x3B, 0x2F, 0x2F, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x5F, 0x66, 0x72, - 0x6F, 0x6D, 0x5F, 0x64, 0x65, 0x70, 0x74, 0x68, 0x28, 0x64, 0x65, 0x70, - 0x74, 0x68, 0x2C, 0x20, 0x55, 0x56, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x2E, 0x7A, 0x20, 0x2A, - 0x3D, 0x20, 0x2D, 0x31, 0x2E, 0x30, 0x66, 0x3B, 0x0D, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x20, - 0x74, 0x72, 0x61, 0x6E, 0x73, 0x6C, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, - 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x76, 0x69, 0x65, 0x77, 0x3B, 0x0D, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x6D, 0x61, 0x74, 0x34, 0x20, 0x69, 0x6E, 0x76, - 0x56, 0x69, 0x65, 0x77, 0x20, 0x3D, 0x20, 0x76, 0x5F, 0x49, 0x6E, 0x76, - 0x56, 0x69, 0x65, 0x77, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, - 0x6E, 0x76, 0x56, 0x69, 0x65, 0x77, 0x5B, 0x33, 0x5D, 0x20, 0x3D, 0x20, - 0x76, 0x65, 0x63, 0x34, 0x28, 0x30, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x30, - 0x2C, 0x20, 0x31, 0x29, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x28, 0x69, - 0x6E, 0x76, 0x56, 0x69, 0x65, 0x77, 0x20, 0x2A, 0x20, 0x76, 0x65, 0x63, - 0x34, 0x28, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x2C, 0x20, 0x31, 0x2E, - 0x30, 0x66, 0x29, 0x29, 0x2E, 0x78, 0x79, 0x7A, 0x3B, 0x0D, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x72, 0x61, 0x6E, 0x64, - 0x6F, 0x6D, 0x56, 0x65, 0x63, 0x20, 0x3D, 0x20, 0x74, 0x65, 0x78, 0x74, - 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, 0x4E, 0x6F, 0x69, 0x73, 0x65, 0x2C, - 0x20, 0x55, 0x56, 0x20, 0x2A, 0x20, 0x75, 0x5F, 0x4E, 0x6F, 0x69, 0x73, - 0x65, 0x53, 0x63, 0x61, 0x6C, 0x65, 0x29, 0x2E, 0x78, 0x79, 0x7A, 0x3B, - 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, - 0x20, 0x74, 0x61, 0x6E, 0x67, 0x65, 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, 0x7A, 0x65, 0x28, 0x72, 0x61, 0x6E, - 0x64, 0x6F, 0x6D, 0x56, 0x65, 0x63, 0x20, 0x2D, 0x20, 0x6E, 0x6F, 0x72, - 0x6D, 0x61, 0x6C, 0x20, 0x2A, 0x20, 0x64, 0x6F, 0x74, 0x28, 0x72, 0x61, - 0x6E, 0x64, 0x6F, 0x6D, 0x56, 0x65, 0x63, 0x2C, 0x20, 0x6E, 0x6F, 0x72, - 0x6D, 0x61, 0x6C, 0x29, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x76, 0x65, 0x63, 0x33, 0x20, 0x62, 0x69, 0x74, 0x61, 0x6E, 0x67, 0x65, - 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x28, 0x6E, - 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x2C, 0x20, 0x74, 0x61, 0x6E, 0x67, 0x65, - 0x6E, 0x74, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x61, - 0x74, 0x33, 0x20, 0x54, 0x42, 0x4E, 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x74, - 0x33, 0x28, 0x74, 0x61, 0x6E, 0x67, 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x62, - 0x69, 0x74, 0x61, 0x6E, 0x67, 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x6E, 0x6F, - 0x72, 0x6D, 0x61, 0x6C, 0x29, 0x3B, 0x0D, 0x0A, 0x0D, 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, - 0x0D, 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, 0x0D, 0x0A, + 0x56, 0x29, 0x2E, 0x72, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, + 0x66, 0x20, 0x28, 0x64, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3E, 0x20, 0x30, + 0x2E, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x66, 0x29, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x73, 0x61, 0x6D, 0x70, - 0x6C, 0x65, 0x50, 0x6F, 0x73, 0x20, 0x3D, 0x20, 0x54, 0x42, 0x4E, 0x20, - 0x2A, 0x20, 0x75, 0x5F, 0x53, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x73, 0x5B, - 0x69, 0x5D, 0x3B, 0x20, 0x2F, 0x2F, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D, - 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x50, 0x6F, - 0x73, 0x2E, 0x7A, 0x20, 0x2A, 0x3D, 0x20, 0x2D, 0x31, 0x2E, 0x30, 0x66, - 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, + 0x20, 0x20, 0x20, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6F, 0x6C, 0x6F, 0x72, + 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x34, 0x28, 0x31, 0x2C, 0x20, 0x31, + 0x2C, 0x20, 0x31, 0x2C, 0x20, 0x30, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, + 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x66, 0x72, 0x61, + 0x67, 0x50, 0x6F, 0x73, 0x20, 0x3D, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, + 0x50, 0x6F, 0x73, 0x46, 0x72, 0x6F, 0x6D, 0x44, 0x65, 0x70, 0x74, 0x68, + 0x28, 0x64, 0x65, 0x70, 0x74, 0x68, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, + 0x3D, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, + 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x2C, 0x20, 0x55, 0x56, 0x29, 0x2E, + 0x78, 0x79, 0x7A, 0x20, 0x2A, 0x20, 0x32, 0x2E, 0x30, 0x20, 0x2D, 0x20, + 0x31, 0x2E, 0x30, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x61, + 0x74, 0x33, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x4D, 0x61, 0x74, + 0x72, 0x69, 0x78, 0x20, 0x3D, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x70, + 0x6F, 0x73, 0x65, 0x28, 0x69, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x65, 0x28, + 0x6D, 0x61, 0x74, 0x33, 0x28, 0x76, 0x5F, 0x56, 0x69, 0x65, 0x77, 0x29, + 0x29, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, + 0x33, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x28, + 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x4D, 0x61, 0x74, 0x72, 0x69, 0x78, + 0x20, 0x2A, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x29, 0x2E, 0x78, 0x79, 0x7A, + 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, + 0x33, 0x20, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D, 0x56, 0x65, 0x63, 0x20, + 0x3D, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, + 0x4E, 0x6F, 0x69, 0x73, 0x65, 0x2C, 0x20, 0x55, 0x56, 0x20, 0x2A, 0x20, + 0x75, 0x5F, 0x4E, 0x6F, 0x69, 0x73, 0x65, 0x53, 0x63, 0x61, 0x6C, 0x65, + 0x29, 0x2E, 0x78, 0x79, 0x7A, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, 0x61, 0x6E, 0x67, 0x65, + 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x69, + 0x7A, 0x65, 0x28, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D, 0x56, 0x65, 0x63, + 0x20, 0x2D, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x2A, 0x20, + 0x64, 0x6F, 0x74, 0x28, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D, 0x56, 0x65, + 0x63, 0x2C, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x29, 0x29, 0x3B, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x62, + 0x69, 0x74, 0x61, 0x6E, 0x67, 0x65, 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x63, + 0x72, 0x6F, 0x73, 0x73, 0x28, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x2C, + 0x20, 0x74, 0x61, 0x6E, 0x67, 0x65, 0x6E, 0x74, 0x29, 0x3B, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x6D, 0x61, 0x74, 0x33, 0x20, 0x54, 0x42, 0x4E, + 0x20, 0x3D, 0x20, 0x6D, 0x61, 0x74, 0x33, 0x28, 0x74, 0x61, 0x6E, 0x67, + 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x62, 0x69, 0x74, 0x61, 0x6E, 0x67, 0x65, + 0x6E, 0x74, 0x2C, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x29, 0x3B, + 0x0D, 0x0A, 0x0D, 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, 0x66, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, + 0x20, 0x69, 0x6E, 0x74, 0x20, 0x6B, 0x65, 0x72, 0x6E, 0x65, 0x6C, 0x43, + 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x36, 0x34, 0x3B, 0x0D, 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, + 0x6B, 0x65, 0x72, 0x6E, 0x65, 0x6C, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x3B, + 0x20, 0x69, 0x2B, 0x2B, 0x29, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, + 0x63, 0x33, 0x20, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x50, 0x6F, 0x73, + 0x20, 0x3D, 0x20, 0x54, 0x42, 0x4E, 0x20, 0x2A, 0x20, 0x75, 0x5F, 0x53, + 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x73, 0x5B, 0x69, 0x5D, 0x3B, 0x20, 0x2F, + 0x2F, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x61, + 0x20, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D, 0x20, 0x70, 0x6F, 0x69, 0x6E, + 0x74, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x50, 0x6F, 0x73, 0x20, 0x3D, 0x20, 0x66, 0x72, 0x61, 0x67, 0x50, 0x6F, 0x73, 0x20, 0x2B, 0x20, 0x73, 0x61, 0x6D, - 0x70, 0x6C, 0x65, 0x50, 0x6F, 0x73, 0x20, 0x2A, 0x20, 0x73, 0x63, 0x61, - 0x6C, 0x65, 0x64, 0x52, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3B, 0x0D, 0x0A, - 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, - 0x63, 0x34, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x3D, 0x20, - 0x76, 0x65, 0x63, 0x34, 0x28, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x50, - 0x6F, 0x73, 0x2C, 0x20, 0x31, 0x2E, 0x30, 0x29, 0x3B, 0x20, 0x2F, 0x2F, - 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x20, 0x34, - 0x2D, 0x76, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x0D, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, - 0x3D, 0x20, 0x76, 0x5F, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x69, - 0x6F, 0x6E, 0x20, 0x2A, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3B, - 0x20, 0x2F, 0x2F, 0x20, 0x70, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, - 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, - 0x63, 0x6C, 0x69, 0x70, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x70, 0x6C, 0x61, - 0x6E, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x78, 0x79, 0x7A, 0x20, 0x2F, - 0x3D, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x77, 0x3B, 0x20, - 0x2F, 0x2F, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x70, - 0x65, 0x72, 0x73, 0x70, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x64, - 0x69, 0x76, 0x69, 0x64, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x78, 0x79, - 0x7A, 0x20, 0x3D, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x78, - 0x79, 0x7A, 0x20, 0x2A, 0x20, 0x30, 0x2E, 0x35, 0x20, 0x2B, 0x20, 0x30, - 0x2E, 0x35, 0x3B, 0x20, 0x2F, 0x2F, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, - 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x28, 0x30, 0x2C, 0x31, - 0x29, 0x20, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x73, - 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3D, - 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, 0x44, - 0x65, 0x70, 0x74, 0x68, 0x2C, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x2E, 0x78, 0x79, 0x29, 0x2E, 0x72, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x70, 0x6C, 0x65, 0x50, 0x6F, 0x73, 0x20, 0x2A, 0x20, 0x75, 0x5F, 0x52, + 0x61, 0x64, 0x69, 0x75, 0x73, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6F, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x34, + 0x28, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x50, 0x6F, 0x73, 0x2C, 0x20, + 0x31, 0x2E, 0x30, 0x29, 0x3B, 0x20, 0x2F, 0x2F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x20, 0x34, 0x2D, 0x76, 0x65, 0x63, + 0x74, 0x6F, 0x72, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x3D, 0x20, 0x76, 0x5F, + 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x2A, + 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3B, 0x20, 0x2F, 0x2F, 0x20, + 0x70, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, 0x63, 0x6C, 0x69, 0x70, + 0x70, 0x69, 0x6E, 0x67, 0x20, 0x70, 0x6C, 0x61, 0x6E, 0x65, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x2E, 0x78, 0x79, 0x7A, 0x20, 0x2F, 0x3D, 0x20, 0x6F, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x2E, 0x77, 0x3B, 0x20, 0x2F, 0x2F, 0x20, 0x70, + 0x65, 0x72, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x70, 0x65, 0x72, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x64, 0x69, 0x76, 0x69, 0x64, + 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x78, 0x79, 0x7A, 0x20, 0x3D, 0x20, + 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x78, 0x79, 0x7A, 0x20, 0x2A, + 0x20, 0x30, 0x2E, 0x35, 0x20, 0x2B, 0x20, 0x30, 0x2E, 0x35, 0x3B, 0x20, + 0x2F, 0x2F, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x6F, 0x72, 0x6D, + 0x20, 0x74, 0x6F, 0x20, 0x28, 0x30, 0x2C, 0x31, 0x29, 0x20, 0x72, 0x61, + 0x6E, 0x67, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x78, 0x20, + 0x3D, 0x20, 0x63, 0x6C, 0x61, 0x6D, 0x70, 0x28, 0x6F, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x2E, 0x78, 0x2C, 0x20, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x30, + 0x31, 0x2C, 0x20, 0x30, 0x2E, 0x39, 0x39, 0x39, 0x29, 0x3B, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x2E, 0x79, 0x20, 0x3D, 0x20, 0x63, 0x6C, 0x61, 0x6D, 0x70, + 0x28, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x79, 0x2C, 0x20, 0x30, + 0x2E, 0x30, 0x30, 0x30, 0x30, 0x31, 0x2C, 0x20, 0x30, 0x2E, 0x39, 0x39, + 0x39, 0x29, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x73, 0x61, 0x6D, + 0x70, 0x6C, 0x65, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3D, 0x20, 0x74, + 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x75, 0x5F, 0x44, 0x65, 0x70, + 0x74, 0x68, 0x2C, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x78, + 0x79, 0x29, 0x2E, 0x78, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x65, 0x70, 0x73, + 0x69, 0x6C, 0x6F, 0x6E, 0x20, 0x3D, 0x20, 0x30, 0x2E, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x31, 0x66, 0x3B, 0x20, 0x2F, 0x2F, 0x20, 0x41, 0x64, 0x6A, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6F, 0x6E, + 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x73, 0x63, 0x65, 0x6E, 0x65, 0x27, + 0x73, 0x20, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x72, - 0x61, 0x6E, 0x67, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x3D, 0x20, - 0x73, 0x6D, 0x6F, 0x6F, 0x74, 0x68, 0x73, 0x74, 0x65, 0x70, 0x28, 0x30, - 0x2E, 0x30, 0x2C, 0x20, 0x31, 0x2E, 0x30, 0x2C, 0x20, 0x73, 0x63, 0x61, - 0x6C, 0x65, 0x64, 0x52, 0x61, 0x64, 0x69, 0x75, 0x73, 0x20, 0x2F, 0x20, - 0x61, 0x62, 0x73, 0x28, 0x28, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x50, - 0x6F, 0x73, 0x2E, 0x7A, 0x29, 0x20, 0x2D, 0x20, 0x73, 0x61, 0x6D, 0x70, - 0x6C, 0x65, 0x44, 0x65, 0x70, 0x74, 0x68, 0x29, 0x29, 0x3B, 0x0D, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, 0x63, 0x63, 0x6C, - 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x2B, 0x3D, 0x20, 0x28, 0x73, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3C, 0x3D, - 0x20, 0x64, 0x65, 0x70, 0x74, 0x68, 0x20, 0x2D, 0x20, 0x75, 0x5F, 0x42, - 0x69, 0x61, 0x73, 0x20, 0x2F, 0x20, 0x31, 0x30, 0x30, 0x2E, 0x30, 0x20, - 0x3F, 0x20, 0x31, 0x2E, 0x30, 0x20, 0x3A, 0x20, 0x30, 0x2E, 0x30, 0x29, - 0x20, 0x2A, 0x20, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x43, 0x68, 0x65, 0x63, - 0x6B, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x0D, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x61, - 0x6F, 0x20, 0x3D, 0x20, 0x31, 0x2E, 0x30, 0x20, 0x2D, 0x20, 0x28, 0x6F, - 0x63, 0x63, 0x6C, 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x2F, 0x20, 0x36, - 0x34, 0x2E, 0x30, 0x29, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, - 0x41, 0x4F, 0x20, 0x3D, 0x20, 0x70, 0x6F, 0x77, 0x28, 0x61, 0x6F, 0x2C, - 0x20, 0x75, 0x5F, 0x53, 0x74, 0x72, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x20, - 0x2A, 0x20, 0x31, 0x30, 0x30, 0x2E, 0x30, 0x29, 0x3B, 0x0D, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6F, 0x6C, 0x6F, 0x72, - 0x20, 0x3D, 0x20, 0x76, 0x65, 0x63, 0x34, 0x28, 0x66, 0x69, 0x6E, 0x61, - 0x6C, 0x41, 0x4F, 0x2C, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x41, 0x4F, - 0x2C, 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6C, 0x41, 0x4F, 0x2C, 0x20, 0x31, - 0x2E, 0x30, 0x29, 0x3B, 0x0D, 0x0A, 0x7D, + 0x65, 0x61, 0x6C, 0x42, 0x69, 0x61, 0x73, 0x20, 0x3D, 0x20, 0x28, 0x2D, + 0x30, 0x2E, 0x30, 0x30, 0x31, 0x20, 0x2F, 0x20, 0x31, 0x30, 0x30, 0x30, + 0x2E, 0x30, 0x66, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x72, 0x61, 0x6E, + 0x67, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x3D, 0x20, 0x73, 0x6D, + 0x6F, 0x6F, 0x74, 0x68, 0x73, 0x74, 0x65, 0x70, 0x28, 0x30, 0x2E, 0x30, + 0x2C, 0x20, 0x31, 0x2E, 0x30, 0x2C, 0x20, 0x28, 0x75, 0x5F, 0x52, 0x61, + 0x64, 0x69, 0x75, 0x73, 0x20, 0x2F, 0x20, 0x35, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x2E, 0x30, 0x66, 0x29, 0x20, 0x2F, 0x20, 0x28, 0x61, 0x62, 0x73, + 0x28, 0x64, 0x65, 0x70, 0x74, 0x68, 0x20, 0x2D, 0x20, 0x73, 0x61, 0x6D, + 0x70, 0x6C, 0x65, 0x44, 0x65, 0x70, 0x74, 0x68, 0x29, 0x29, 0x29, 0x20, + 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, + 0x63, 0x63, 0x6C, 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x2B, 0x3D, 0x20, + 0x28, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x44, 0x65, 0x70, 0x74, 0x68, + 0x20, 0x3C, 0x3D, 0x20, 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2E, 0x7A, + 0x20, 0x2B, 0x20, 0x72, 0x65, 0x61, 0x6C, 0x42, 0x69, 0x61, 0x73, 0x20, + 0x3F, 0x20, 0x31, 0x2E, 0x30, 0x66, 0x20, 0x3A, 0x20, 0x30, 0x2E, 0x30, + 0x66, 0x29, 0x20, 0x2A, 0x20, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x43, 0x68, + 0x65, 0x63, 0x6B, 0x20, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x61, 0x6F, 0x20, 0x3D, 0x20, 0x31, + 0x2E, 0x30, 0x20, 0x2D, 0x20, 0x70, 0x6F, 0x77, 0x28, 0x6F, 0x63, 0x63, + 0x6C, 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x75, 0x5F, 0x53, 0x74, + 0x72, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x29, 0x20, 0x2F, 0x20, 0x36, 0x34, + 0x2E, 0x30, 0x66, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x46, 0x72, + 0x61, 0x67, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x76, 0x65, + 0x63, 0x34, 0x28, 0x61, 0x6F, 0x2C, 0x20, 0x61, 0x6F, 0x2C, 0x20, 0x61, + 0x6F, 0x2C, 0x20, 0x31, 0x2E, 0x30, 0x66, 0x29, 0x3B, 0x0D, 0x0A, 0x7D, + }; unsigned int Resources_Shaders_ssao_shader_len = sizeof(Resources_Shaders_ssao_shader); diff --git a/Resources/Shaders/ssao.shader b/Resources/Shaders/ssao.shader index 8495339d..fc59ffff 100644 --- a/Resources/Shaders/ssao.shader +++ b/Resources/Shaders/ssao.shader @@ -27,8 +27,8 @@ void main() #shader fragment #version 440 core -uniform sampler2D u_Depth; uniform sampler2D u_Normal; +uniform sampler2D u_Depth; uniform sampler2D u_Noise; uniform int u_KernelSize = 64; @@ -51,7 +51,7 @@ out vec4 FragColor; float linearize_depth(float d, float zNear, float zFar) { - return zNear * zFar / (zFar + d * (zNear - zFar)); + return (2.0 * zNear * zFar) / (zFar + zNear - d * (zFar - zNear)) / 400.0; } vec3 WorldPosFromDepth(float depth) @@ -64,89 +64,53 @@ vec3 WorldPosFromDepth(float depth) // Perspective division viewSpacePosition /= viewSpacePosition.w; - vec4 worldSpacePosition = v_InvView * viewSpacePosition; - - return worldSpacePosition.xyz; -} - -vec3 ViewPosFromDepth(float depth) -{ - float z = depth * 2.0 - 1.0; - - vec4 clipSpacePosition = vec4(UV * 2.0 - 1.0, z, 1.0); - vec4 viewSpacePosition = v_InvProjection * clipSpacePosition; - viewSpacePosition.xyz /= viewSpacePosition.w; - return viewSpacePosition.xyz; } -vec3 normal_from_depth(float depth, vec2 texcoords) { - - const vec2 offset1 = vec2(0.0,0.0002); - const vec2 offset2 = vec2(0.0002,0.0); - - float depth1 = texture(u_Depth, UV + offset1).r; - float depth2 = texture(u_Depth, UV + offset2).r; - - vec3 p1 = vec3(offset1, depth1 - depth); - vec3 p2 = vec3(offset2, depth2 - depth); - - vec3 normal = cross(p1, p2); - normal.z = -normal.z; - - return normalize(normal); -} void main() { float depth = texture(u_Depth, UV).r; if (depth > 0.9999999f) { - FragColor = vec4(0, 0, 0, 0); + FragColor = vec4(1, 1, 1, 0); return; } - const float SCALING_NEAR = 0.92; - float depthScaler = (depth - SCALING_NEAR) / (1.0 - SCALING_NEAR); + vec3 fragPos = WorldPosFromDepth(depth); + vec3 worldSpaceNormal = texture(u_Normal, UV).xyz * 2.0 - 1.0; + mat3 normalMatrix = transpose(inverse(mat3(v_View))); + vec3 normal = (normalMatrix * worldSpaceNormal).xyz; - const float minRadius = 0.05f; - const float maxRadius = 1.2f; - const float scalerPow = 1.8f; - depthScaler = min(max(pow(depthScaler, scalerPow), minRadius), maxRadius); - float scaledRadius = u_Radius; - - vec3 fragPos = ViewPosFromDepth(depth); - vec3 normal = texture(u_Normal, UV).xyz * 2.0 - 1.0;//normal_from_depth(depth, UV); - normal.z *= -1.0f; - // Remove translation from view; - mat4 invView = v_InvView; - invView[3] = vec4(0, 0, 0, 1); - - normal = (invView * vec4(normal, 1.0f)).xyz; vec3 randomVec = texture(u_Noise, UV * u_NoiseScale).xyz; vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal)); vec3 bitangent = cross(normal, tangent); mat3 TBN = mat3(tangent, bitangent, normal); - float occlusion = 0.0; - for (int i = 0; i < 64; i++) + float occlusion = 0.0f; + + const int kernelCount = 64; + for (int i = 0; i < kernelCount; i++) { vec3 samplePos = TBN * u_Samples[i]; // generate a random point - samplePos.z *= -1.0f; - samplePos = fragPos + samplePos * scaledRadius; + samplePos = fragPos + samplePos * u_Radius; vec4 offset = vec4(samplePos, 1.0); // make it a 4-vector offset = v_Projection * offset; // project on the near clipping plane offset.xyz /= offset.w; // perform perspective divide offset.xyz = offset.xyz * 0.5 + 0.5; // transform to (0,1) range - float sampleDepth = texture(u_Depth, offset.xy).r; - float rangeCheck = smoothstep(0.0, 1.0, scaledRadius / abs((samplePos.z) - sampleDepth)); - occlusion += (sampleDepth <= depth - u_Bias / 100.0 ? 1.0 : 0.0) * rangeCheck; + + offset.x = clamp(offset.x, 0.00001, 0.999); + offset.y = clamp(offset.y, 0.00001, 0.999); + + float sampleDepth = texture(u_Depth, offset.xy).x; + float epsilon = 0.000001f; // Adjust based on your scene's scale + float realBias = (-0.001 / 1000.0f); + float rangeCheck = smoothstep(0.0, 1.0, (u_Radius / 500000.0f) / (abs(depth - sampleDepth))) ; + occlusion += (sampleDepth <= offset.z + realBias ? 1.0f : 0.0f) * rangeCheck ; } - - float ao = 1.0 - (occlusion / 64.0); - - float finalAO = pow(ao, u_Strength * 100.0); - FragColor = vec4(finalAO, finalAO, finalAO, 1.0); + + float ao = 1.0 - pow(occlusion, u_Strength) / 64.0f; + FragColor = vec4(ao, ao, ao, 1.0f); } \ No newline at end of file