diff --git a/imgui.ini b/imgui.ini new file mode 100644 index 0000000..7162e92 --- /dev/null +++ b/imgui.ini @@ -0,0 +1,41 @@ +[Window][Debug##Default] +Pos=876,8 +Size=315,195 +Collapsed=0 +DockId=0x00000008,0 + +[Window][Dear ImGui Demo] +Pos=1193,178 +Size=62,25 +Collapsed=0 +DockId=0x00000007,0 + +[Window][Game module window] +Pos=1193,8 +Size=62,50 +Collapsed=0 +DockId=0x00000004,0 + +[Window][Time] +Pos=1193,60 +Size=62,49 +Collapsed=0 +DockId=0x00000005,0 + +[Window][Active Modules] +Pos=1193,111 +Size=62,65 +Collapsed=0 +DockId=0x00000006,0 + +[Docking][Data] +DockNode ID=0x00000001 Pos=1196,188 Size=379,195 Split=X + DockNode ID=0x00000008 Parent=0x00000001 SizeRef=652,419 HiddenTabBar=1 Selected=0x55954704 + DockNode ID=0x00000009 Parent=0x00000001 SizeRef=129,419 Split=Y + DockNode ID=0x00000002 Parent=0x00000009 SizeRef=219,34 Split=Y Selected=0xFC1D20C0 + DockNode ID=0x00000004 Parent=0x00000002 SizeRef=219,64 Selected=0xFC1D20C0 + DockNode ID=0x00000005 Parent=0x00000002 SizeRef=219,62 Selected=0xE75A179E + DockNode ID=0x00000003 Parent=0x00000009 SizeRef=219,31 Split=Y Selected=0xEE305C78 + DockNode ID=0x00000006 Parent=0x00000003 SizeRef=219,142 Selected=0xEE305C78 + DockNode ID=0x00000007 Parent=0x00000003 SizeRef=219,55 Selected=0xE87781F4 + diff --git a/projs/shadow/shadow-engine/CMakeLists.txt b/projs/shadow/shadow-engine/CMakeLists.txt index 75f7ae0..e5e2434 100644 --- a/projs/shadow/shadow-engine/CMakeLists.txt +++ b/projs/shadow/shadow-engine/CMakeLists.txt @@ -9,11 +9,13 @@ FILE(GLOB_RECURSE SOURCES core/src/*.cpp shadow-renderer/src/*.cpp shadow-reflection/src/*.cpp + shadow-utility/src/*.cpp ) FILE(GLOB_RECURSE HEADERS core/inc/*.h shadow-renderer/inc/*.h shadow-reflection/inc/*.h + shadow-utility/inc/*.h ) add_library(shadow-engine SHARED ${SOURCES} $) @@ -24,6 +26,7 @@ target_include_directories(shadow-engine core/inc shadow-renderer/inc shadow-reflection/inc + shadow-utility/inc ${glm_SOURCE_DIR} INTERFACE ${imgui_SOURCE_DIR} diff --git a/projs/shadow/shadow-engine/core/inc/core/Module.h b/projs/shadow/shadow-engine/core/inc/core/Module.h index 6baa0c3..1f80379 100644 --- a/projs/shadow/shadow-engine/core/inc/core/Module.h +++ b/projs/shadow/shadow-engine/core/inc/core/Module.h @@ -2,7 +2,8 @@ #define UMBRA_MODULE_H #include "SHObject.h" -#include +#include "SDL_events.h" +#include "vlkx/vulkan/abstraction/Commands.h" namespace ShadowEngine { @@ -29,13 +30,17 @@ namespace ShadowEngine { /// /// update is called each frame /// - virtual void Update() = 0; + virtual void Update(int frame) = 0; + + virtual void Recreate() = 0; virtual void PreRender() = 0; - virtual void Render() = 0; + virtual void Render(VkCommandBuffer& commands, int frame) = 0; - virtual void LateRender() = 0; + virtual void LateRender(VkCommandBuffer& commands, int frame) = 0; + + virtual void OverlayRender() = 0; virtual void AfterFrameEnd() = 0; @@ -52,6 +57,21 @@ namespace ShadowEngine { }; }; + /** + * A class especially for modules that are renderers. + * Allows the engine to access state from the renderer independent of implementation. + */ + class RendererModule : public Module { + public: + // Begin the render pass using the given commands. + // Will call out through the regular modules to gather geometry to render. + virtual void BeginRenderPass(const std::unique_ptr& commands) = 0; + + virtual void EnableEditor() = 0; + + virtual VkExtent2D GetRenderExtent() = 0; + }; + } // ShadowEngine #endif //UMBRA_MODULE_H diff --git a/projs/shadow/shadow-engine/core/inc/core/ModuleManager.h b/projs/shadow/shadow-engine/core/inc/core/ModuleManager.h index 503338e..261b6eb 100644 --- a/projs/shadow/shadow-engine/core/inc/core/ModuleManager.h +++ b/projs/shadow/shadow-engine/core/inc/core/ModuleManager.h @@ -11,22 +11,29 @@ namespace ShadowEngine { public: std::shared_ptr module; std::string domain; + + // Reinterpret this module as if it were a Renderer Module. + // A shortcut for `std::static_pointer_cast>(ShadowEngine::ModuleManager::instance->GetModule("renderer")) + std::shared_ptr operator->() const { return std::static_pointer_cast(module); } }; class ModuleManager { public: - static ModuleManager *instance; + static API ModuleManager *instance; + static ModuleManager* getInstance() { return instance; } std::list modules; + ModuleRef renderer; ModuleManager(); ~ModuleManager(); - void PushModule(std::shared_ptr module, std::string domain); + void PushModule(const std::shared_ptr& module, const std::string& domain); - Module &GetModule(std::string name); + Module &GetModule(const std::string& name); + /* template T *GetModuleByType() { for (auto &module: modules) { @@ -35,15 +42,19 @@ namespace ShadowEngine { } //SH_CORE_ERROR("Can't find the module {0}", T::Type()); return nullptr; - } + } */ void Init(); - void Update(); + void Update(int frame); - void LateRender(); + void LateRender(VkCommandBuffer& commands, int frame); - void Render(); + void OverlayRender(); + + void Recreate(); + + void Render(VkCommandBuffer& commands, int frame); void PreRender(); diff --git a/projs/shadow/shadow-engine/core/inc/core/SDL2Module.h b/projs/shadow/shadow-engine/core/inc/core/SDL2Module.h index 91e784f..50137db 100644 --- a/projs/shadow/shadow-engine/core/inc/core/SDL2Module.h +++ b/projs/shadow/shadow-engine/core/inc/core/SDL2Module.h @@ -8,7 +8,7 @@ #include "Module.h" #include "ShadowWindow.h" -#include +#include "SDL.h" namespace ShadowEngine { @@ -23,11 +23,15 @@ namespace ShadowEngine { void PreInit() override; - void Update() override; + void Update(int frame) override; - void Render() override; + void Recreate() override; - void LateRender() override; + void Render(VkCommandBuffer& commands, int frame) override; + + void OverlayRender() override; + + void LateRender(VkCommandBuffer& commands, int frame) override; std::string GetName() override; diff --git a/projs/shadow/shadow-engine/core/inc/core/ShadowApplication.h b/projs/shadow/shadow-engine/core/inc/core/ShadowApplication.h index b51bf49..3e39cbe 100644 --- a/projs/shadow/shadow-engine/core/inc/core/ShadowApplication.h +++ b/projs/shadow/shadow-engine/core/inc/core/ShadowApplication.h @@ -68,6 +68,6 @@ namespace ShadowEngine { void Init(); void Start(); - - }; + void PollEvents(); + }; } \ No newline at end of file diff --git a/projs/shadow/shadow-engine/core/inc/core/ShadowWindow.h b/projs/shadow/shadow-engine/core/inc/core/ShadowWindow.h index 774738d..295ee49 100644 --- a/projs/shadow/shadow-engine/core/inc/core/ShadowWindow.h +++ b/projs/shadow/shadow-engine/core/inc/core/ShadowWindow.h @@ -1,6 +1,6 @@ #pragma once -#include +#include "SDL.h" namespace ShadowEngine { diff --git a/projs/shadow/shadow-engine/core/inc/core/Time.h b/projs/shadow/shadow-engine/core/inc/core/Time.h index c0fcd66..4f568f7 100644 --- a/projs/shadow/shadow-engine/core/inc/core/Time.h +++ b/projs/shadow/shadow-engine/core/inc/core/Time.h @@ -1,14 +1,20 @@ #pragma once + +#include "exports.h" + class Time { - static int NOW; public: - static int LAST; + static API int NOW; + static API int LAST; - static double deltaTime; - static double deltaTime_ms; + static API double deltaTime; + static API double deltaTime_ms; + + static API double timeSinceStart; + static API double startTime; static void UpdateTime(); }; diff --git a/projs/shadow/shadow-engine/core/inc/debug/DebugModule.h b/projs/shadow/shadow-engine/core/inc/debug/DebugModule.h index 57aa3ed..20f32e6 100644 --- a/projs/shadow/shadow-engine/core/inc/debug/DebugModule.h +++ b/projs/shadow/shadow-engine/core/inc/debug/DebugModule.h @@ -5,8 +5,9 @@ #ifndef UMBRA_DEBUGMODULE_H #define UMBRA_DEBUGMODULE_H -#include +#include "SDL_events.h" #include "core/Module.h" +#include "imgui.h" namespace ShadowEngine::Debug { @@ -17,15 +18,19 @@ namespace ShadowEngine::Debug { bool active; public: - void Render() override; + void Render(VkCommandBuffer& commands, int frame) override {}; void PreInit() override { }; void Init() override { }; - void Update() override { }; + void Recreate() override {}; - void LateRender() override { }; + void OverlayRender() override; + + void Update(int frame) override { }; + + void LateRender(VkCommandBuffer& commands, int frame) override { }; void AfterFrameEnd() override { }; diff --git a/projs/shadow/shadow-engine/core/inc/exports.h b/projs/shadow/shadow-engine/core/inc/exports.h index 97d9502..e46ec7a 100644 --- a/projs/shadow/shadow-engine/core/inc/exports.h +++ b/projs/shadow/shadow-engine/core/inc/exports.h @@ -6,9 +6,9 @@ #if defined(_WIN32) # if defined(EXPORTING_SH_ENGINE) -# define SH_EXPORT __declspec(dllexport) +# define API __declspec(dllexport) # else -# define SH_EXPORT __declspec(dllimport) +# define API __declspec(dllimport) # endif #else // non windows # define SH_EXPORT diff --git a/projs/shadow/shadow-engine/core/src/core/App2.txt b/projs/shadow/shadow-engine/core/src/core/App2.txt new file mode 100644 index 0000000..a5ba809 --- /dev/null +++ b/projs/shadow/shadow-engine/core/src/core/App2.txt @@ -0,0 +1,348 @@ +#include "ShadowApplication.h" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +#define GLM_FORCE_DEPTH_ZERO_TO_ONE +#include "time.h" +#include "imgui.h" +#include "imgui_impl_vulkan.h" +#include "imgui_impl_sdl.h" +#include +#include "vlkx/render/Camera.h" +#include "vlkx/render/render_pass/ScreenRenderPass.h" +#include "spdlog/spdlog.h" +#include "vlkx/vulkan/abstraction/Commands.h" +#include "vlkx/render/Geometry.h" +#include "temp/model/Builder.h" + +#define CATCH(x) \ + try { x } catch (std::exception& e) { spdlog::error(e.what()); exit(0); } + +namespace ShadowEngine { + + struct SkyboxTransform { + alignas(sizeof(glm::mat4)) glm::mat4 value; + }; + + struct PlanetTransform { + alignas(sizeof(glm::mat4)) glm::mat4 model; + alignas(sizeof(glm::mat4)) glm::mat4 projection; + }; + + struct Light { + alignas(sizeof(glm::vec4)) glm::vec4 dirTime; + }; + + std::unique_ptr passManager; + std::unique_ptr renderCommands; + std::unique_ptr camera; + std::unique_ptr light; + + std::unique_ptr skyboxConstant; + std::unique_ptr planetConstant; + std::unique_ptr skyboxModel; + std::unique_ptr planetModel; + std::unique_ptr asteroidModel; + + float aspectRatio; + + ShadowApplication* ShadowApplication::instance = nullptr; + + ShadowApplication::ShadowApplication(int argc, char* argv[]) + { + instance = this; + + if(argc > 1) + { + for (size_t i = 0; i < argc; i++) + { + std::string param(argv[i]); + if(param == "-no-gui") + { + this->no_gui = true; + } + if(param == "-game") + { + this->game = argv[i+1]; + } + } + } + + //game = _setupFunc(); + } + + + ShadowApplication::~ShadowApplication() + { + } + + void ShadowApplication::Init() + { + // Initialize SDL. SDL_Init will return -1 if it fails. + if ( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) { + //std::cout << "Error initializing SDL: " << SDL_GetError() << std::endl; + //system("pause"); + // End the program + //return 1; + } + + window_ = new ShadowWindow(800,800); + + CATCH(VulkanManager::getInstance()->initVulkan(window_->sdlWindowPtr);) + + renderCommands = std::make_unique(2); + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + + VkDescriptorPool imGuiPool; + VulkanManager* vk = VulkanManager::getInstance(); + VkDescriptorPoolSize pool_sizes[] = + { + { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, + { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } + }; + + VkDescriptorPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes); + pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); + pool_info.pPoolSizes = pool_sizes; + vkCreateDescriptorPool(vk->getDevice()->logical, &pool_info, VK_NULL_HANDLE, &imGuiPool); + + // Setup Platform/Renderer backends + ImGui_ImplSDL2_InitForVulkan(window_->sdlWindowPtr); + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.Instance = vk->getVulkan(); + init_info.PhysicalDevice = vk->getDevice()->physical; + init_info.Device = vk->getDevice()->logical; + init_info.QueueFamily = vk->getDevice()->queueData.graphics; + init_info.Queue = vk->getDevice()->graphicsQueue; + init_info.PipelineCache = VK_NULL_HANDLE; + init_info.DescriptorPool = imGuiPool; + init_info.Subpass = 1; + init_info.MinImageCount = vk->getSwapchain()->images.size(); + init_info.ImageCount = vk->getSwapchain()->images.size(); + init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + init_info.Allocator = VK_NULL_HANDLE; + init_info.CheckVkResultFn = nullptr; + + vlkxtemp::ModelBuilder::ShaderPool pool; + + renderCommands = std::make_unique(2); + skyboxConstant = std::make_unique(sizeof(SkyboxTransform), 2); + planetConstant = std::make_unique(sizeof(PlanetTransform), 2); + light = std::make_unique(sizeof(Light), 2); + + aspectRatio = (float) window_->Width / window_->Height; + + vlkx::Camera::Config conf {}; + camera = vlkx::UserPerspectiveCamera::create( {}, {}, { 110, aspectRatio }); + + using vlkxtemp::ModelBuilder; + + + const vlkx::RefCountedTexture::CubemapLocation skybox { + "resources/planets/bg", + { + "left.png", "right.png", + "top.png", "bottom.png", + "front.png", "back.png" + } + }; + + skyboxModel = ModelBuilder { + "Skybox", 2, aspectRatio, + ModelBuilder::SingleMeshModel { "resources/planets/skybox.obj", 1, + { { ModelBuilder::TextureType::Cubemap, { { skybox } } } } + }} + .bindTextures(ModelBuilder::TextureType::Cubemap, 1) + .pushStage(VK_SHADER_STAGE_VERTEX_BIT) + .pushConstant(skyboxConstant.get(), 0) + .shader(VK_SHADER_STAGE_VERTEX_BIT, "resources/planets/skybox.vert.spv") + .shader(VK_SHADER_STAGE_FRAGMENT_BIT, "resources/planets/skybox.frag.spv") + .build(); + + planetModel = ModelBuilder { + "Walrus", 2, aspectRatio, + ModelBuilder::SingleMeshModel {"resources/walrus/walrus.obj", 1, + {{ ModelBuilder::TextureType::Diffuse, { { "resources/walrus/texture.png" } } } } + }} + .bindTextures(ModelBuilder::TextureType::Diffuse, 2) + .uniform(VK_SHADER_STAGE_FRAGMENT_BIT, {{1, 1}}) + .uniformBuffer(1, *light) + .pushStage(VK_SHADER_STAGE_VERTEX_BIT) + .pushConstant(planetConstant.get(), 0) + .shader(VK_SHADER_STAGE_VERTEX_BIT, "resources/walrus/walrus.vert.spv") + .shader(VK_SHADER_STAGE_FRAGMENT_BIT, "resources/walrus/walrus.frag.spv") + .build(); + + passManager = std::make_unique(vlkx::RendererConfig { 2 }); + + passManager->initializeRenderPass(); + + skyboxModel->update(true, VulkanManager::getInstance()->getSwapchain()->extent, VK_SAMPLE_COUNT_1_BIT, *passManager->getPass(), 0); + int cursorX, cursorY; + SDL_GetMouseState(&cursorX, &cursorY); + camera->setPos({ cursorX, cursorY }); + + planetModel->update(true, VulkanManager::getInstance()->getSwapchain()->extent, VK_SAMPLE_COUNT_1_BIT, *passManager->getPass(), 0); + + ImGui_ImplVulkan_Init(&init_info, **passManager->getPass()); + // Upload Fonts + VkTools::immediateExecute([](const VkCommandBuffer& commands) { ImGui_ImplVulkan_CreateFontsTexture(commands); }, VulkanManager::getInstance()->getDevice()); + + SDL_SetRelativeMouseMode(SDL_TRUE); + } + + void printMatrix(glm::mat4 mat) { + for (size_t i = 0; i < 4; i++) { + for (size_t j = 0; j < 4; j++) { + std::cout << mat[i][j] << " "; + } + std::cout << std::endl; + } + + std::cout << std::endl << std::endl; + } + + void updateData(int frame) { + const float elapsed_time = Time::timeSinceStart; + + const glm::vec3 lightDir{glm::sin(elapsed_time * 0.0006f), -0.3f, + glm::cos(elapsed_time * 0.0006f)}; + *light->getData(frame) = + {glm::vec4{lightDir, elapsed_time}}; + light->upload(frame); + + glm::mat4 modelMatrix { 1 }; + modelMatrix = glm::rotate(modelMatrix, elapsed_time * glm::radians(0.0005f), glm::vec3 { 0, 1, 0 }); + const vlkx::Camera& cam = camera->getCamera(); + + const glm::mat4 view = glm::lookAt(glm::vec3{3.0f}, glm::vec3{0.0f}, + glm::vec3{0.0f, 1.0f, 0.0f}); + const glm::mat4 proj = glm::perspective( + glm::radians(45.0f), aspectRatio, + 0.1f, 100.0f); + + glm::mat4 planetProjection = cam.getProjMatrix() * cam.getViewMatrix(); + *planetConstant->getData(frame) = { modelMatrix, planetProjection }; + glm::mat4 skyboxMat = cam.getProjMatrix() * cam.getSkyboxView(); + skyboxConstant->getData(frame)->value = skyboxMat; + } + + void imGuiStartDraw() { + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + } + void imGuiEndDraw(const VkCommandBuffer& commands) { + ImGui::Render(); + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commands); + } + + void showDebugWindow(std::unique_ptr* cam) { + #define camPos cam->get()->getCamera().getPosition() + #define camFwd cam->get()->getCamera().getForward() + ImGui::Begin("Camera Debug"); + ImGui::Text("Camera position: (x %f, y %f, z %f)", camPos.x, camPos.y, camPos.z ); + ImGui::Text("Camera target: (x %f, y %f, z %f)", camPos.x + camFwd.x, camPos.y + camFwd.y, camPos.z + camFwd.z); + ImGui::Text("Camera FOV: %f", cam->get()->getCamera().getFieldOfView()); + ImGui::End(); + } + + void ShadowApplication::PollEvents() { + SDL_Event event; + while (SDL_PollEvent(&event)) { // poll until all events are handled! + ImGui_ImplSDL2_ProcessEvent(&event); + + switch(event.type) { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case SDLK_ESCAPE: + camera->reset(); break; + case SDLK_w: + camera->press(vlkx::Camera::Input::Up, Time::deltaTime); break; + case SDLK_s: + camera->press(vlkx::Camera::Input::Down, Time::deltaTime); break; + case SDLK_a: + camera->press(vlkx::Camera::Input::Left, Time::deltaTime); break; + case SDLK_d: + camera->press(vlkx::Camera::Input::Right, Time::deltaTime); break; + } break; + case SDL_MOUSEMOTION: + camera->move(-event.motion.xrel, -event.motion.yrel); break; + + case SDL_MOUSEWHEEL: + camera->scroll(event.wheel.y, 1, 170); break; + case SDL_QUIT: + running = false; break; + } + } + } + + void ShadowApplication::Start() + { + const auto update = [](const int frame) { updateData(frame); }; + + while (running) + { + PollEvents(); + + const auto result = renderCommands->execute(renderCommands->getFrame(), VulkanManager::getInstance()->getSwapchain()->swapChain, update, + [](const VkCommandBuffer& buffer, uint32_t frame) { + passManager->getPass()->execute(buffer, frame, { + // Render our model + [&frame](const VkCommandBuffer& commands) { + planetModel->draw(commands, frame, 1); + skyboxModel->draw(commands, frame, 1); + }, + // Render ImGUI + [&](const VkCommandBuffer& commands) { + imGuiStartDraw(); + + bool showDemo = true; + //if (showDemo) + // ImGui::ShowDemoWindow(&showDemo); + + showDebugWindow(&camera); + + imGuiEndDraw(commands); + } + }); + }); + + if (result.has_value()) + throw std::runtime_error("Resizing is not implemented"); + + renderCommands->nextFrame(); + + Time::UpdateTime(); + + camera->active(true); + } + + vkDeviceWaitIdle(VulkanManager::getInstance()->getDevice()->logical); + + ImGui_ImplVulkan_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + + SDL_DestroyWindow(window_->sdlWindowPtr); + SDL_Quit(); + } +} diff --git a/projs/shadow/shadow-engine/core/src/core/ModuleManager.cpp b/projs/shadow/shadow-engine/core/src/core/ModuleManager.cpp index b4b1b4c..e031243 100644 --- a/projs/shadow/shadow-engine/core/src/core/ModuleManager.cpp +++ b/projs/shadow/shadow-engine/core/src/core/ModuleManager.cpp @@ -18,17 +18,18 @@ ShadowEngine::ModuleManager::ModuleManager() } ShadowEngine::ModuleManager::~ModuleManager() -{ -} += default; -void ShadowEngine::ModuleManager::PushModule(std::shared_ptr module, const std::string domain) +void ShadowEngine::ModuleManager::PushModule(const std::shared_ptr& module, const std::string& domain) { ModuleRef r = {module, domain}; modules.emplace_back(r); + if (domain == "renderer") + renderer = r; module->PreInit(); } -ShadowEngine::Module& ShadowEngine::ModuleManager::GetModule(std::string name) +ShadowEngine::Module& ShadowEngine::ModuleManager::GetModule(const std::string& name) { for (auto& module : modules) { @@ -72,30 +73,47 @@ void ShadowEngine::ModuleManager::Event(SDL_Event* evt) } } -void ShadowEngine::ModuleManager::Update() +void ShadowEngine::ModuleManager::Update(int frame) { for (auto& module : modules) { - module.module->Update(); + module.module->Update(frame); } } -void ShadowEngine::ModuleManager::LateRender() +void ShadowEngine::ModuleManager::LateRender(VkCommandBuffer& commands, int frame) { for (auto& module : modules) { - module.module->LateRender(); + module.module->LateRender(commands, frame); } } -void ShadowEngine::ModuleManager::Render() +void ShadowEngine::ModuleManager::Render(VkCommandBuffer& commands, int frame) { for (auto& module : modules) { - module.module->Render(); + module.module->Render(commands, frame); } } +void ShadowEngine::ModuleManager::OverlayRender() +{ + for (auto& module : modules) + { + module.module->OverlayRender(); + } +} + +void ShadowEngine::ModuleManager::Recreate() +{ + for (auto& module : modules) + { + module.module->Recreate(); + } +} + + void ShadowEngine::ModuleManager::AfterFrameEnd() { for (auto& module : modules) diff --git a/projs/shadow/shadow-engine/core/src/core/SDL2Module.cpp b/projs/shadow/shadow-engine/core/src/core/SDL2Module.cpp index 09382dd..e368d2e 100644 --- a/projs/shadow/shadow-engine/core/src/core/SDL2Module.cpp +++ b/projs/shadow/shadow-engine/core/src/core/SDL2Module.cpp @@ -21,20 +21,20 @@ void ShadowEngine::SDL2Module::PreInit() { //return 1; } - _window = new ShadowWindow(800,450); + _window = new ShadowWindow(1280,720); + SDL_SetWindowResizable(_window->sdlWindowPtr, SDL_TRUE); + //SDL_SetRelativeMouseMode(SDL_TRUE); } -void ShadowEngine::SDL2Module::Update() { +void ShadowEngine::SDL2Module::Update(int frame) {} -} +void ShadowEngine::SDL2Module::Recreate() {} -void ShadowEngine::SDL2Module::Render() { +void ShadowEngine::SDL2Module::Render(VkCommandBuffer& commands, int frame) {} -} +void ShadowEngine::SDL2Module::OverlayRender() {} -void ShadowEngine::SDL2Module::LateRender() { - -} +void ShadowEngine::SDL2Module::LateRender(VkCommandBuffer& commands, int frame) {} std::string ShadowEngine::SDL2Module::GetName() { return this->GetType(); diff --git a/projs/shadow/shadow-engine/core/src/core/ShadowApplication.cpp b/projs/shadow/shadow-engine/core/src/core/ShadowApplication.cpp index 2448ecb..4aa26bc 100644 --- a/projs/shadow/shadow-engine/core/src/core/ShadowApplication.cpp +++ b/projs/shadow/shadow-engine/core/src/core/ShadowApplication.cpp @@ -1,17 +1,14 @@ -#include "core/ShadowApplication.h" +#define STB_IMAGE_IMPLEMENTATION +#include "core/ShadowApplication.h" #include "core/Time.h" #include "core/SDL2Module.h" #include "debug/DebugModule.h" #include "dylib.hpp" - - +#include "vlkx/vulkan/abstraction/Commands.h" #include -#include #include -#include -#include -#include +#include #include #define CATCH(x) \ @@ -23,6 +20,8 @@ namespace ShadowEngine { ShadowApplication* ShadowApplication::instance = nullptr; + std::unique_ptr renderCommands; + ShadowApplication::ShadowApplication(int argc, char* argv[]) { instance = this; @@ -70,23 +69,17 @@ namespace ShadowEngine { void ShadowApplication::Init() { - spdlog::info("Starting Shadow Engine!"); + moduleManager.PushModule(std::make_shared(),"core"); + auto renderer = std::make_shared(); + renderer->EnableEditor(); + moduleManager.PushModule(renderer, "renderer"); loadGame(); - printf("exe side: %p \n", VulkanManager::getInstance()); - printf("exe next ID: %llu \n", ShadowEngine::SHObject::GenerateId()); - - moduleManager.PushModule(std::make_shared(),"core"); moduleManager.PushModule(std::make_shared(), "core"); moduleManager.Init(); - - auto sdl2module = moduleManager.GetModuleByType(); - - window_ = sdl2module->_window; - - + renderCommands = std::make_unique(2); } void ShadowApplication::Start() @@ -100,16 +93,14 @@ namespace ShadowEngine { running = false; } - moduleManager.Update(); moduleManager.PreRender(); - VulkanManager::getInstance()->startDraw(); - moduleManager.Render(); - - moduleManager.LateRender(); - VulkanManager::getInstance()->endDraw(); + moduleManager.renderer->BeginRenderPass(renderCommands); moduleManager.AfterFrameEnd(); + + renderCommands->nextFrame(); + Time::UpdateTime(); } moduleManager.Destroy(); diff --git a/projs/shadow/shadow-engine/core/src/core/Time.cpp b/projs/shadow/shadow-engine/core/src/core/Time.cpp index a76e180..650504d 100644 --- a/projs/shadow/shadow-engine/core/src/core/Time.cpp +++ b/projs/shadow/shadow-engine/core/src/core/Time.cpp @@ -1,20 +1,27 @@ #include "core/Time.h" -//#include -//#include +#include -int Time::NOW = 0;//SDL_GetPerformanceCounter(); -int Time::LAST = 0; -double Time::deltaTime_ms = 0; -double Time::deltaTime = 0; +API int Time::NOW = 0;//SDL_GetPerformanceCounter(); +API int Time::LAST = 0; +API double lastFrame = 0; +API double Time::deltaTime_ms = 0; +API double Time::deltaTime = 0; +API double Time::startTime = 0; +API double Time::timeSinceStart = 0; void Time::UpdateTime() { - /* - NOW = SDL_GetTicks(); - deltaTime_ms = LAST > 0 ? (NOW - LAST) *10 : (1.0f / 60.0f); - deltaTime_ms = deltaTime_ms == 0 ? (1.0f / 60.0f) : deltaTime_ms; + using namespace std::chrono; + auto now = system_clock::now(); + auto now_ms = time_point_cast(now); - LAST = NOW; - deltaTime = deltaTime_ms * 0.001; - */ + auto value = now_ms.time_since_epoch(); + double duration = value.count(); + + deltaTime = duration - lastFrame; + if (startTime == 0) + startTime = duration; + timeSinceStart = duration - startTime; + + lastFrame = duration; } diff --git a/projs/shadow/shadow-engine/core/src/debug/DebugModule.cpp b/projs/shadow/shadow-engine/core/src/debug/DebugModule.cpp index 624ab8e..b70de7e 100644 --- a/projs/shadow/shadow-engine/core/src/debug/DebugModule.cpp +++ b/projs/shadow/shadow-engine/core/src/debug/DebugModule.cpp @@ -9,29 +9,26 @@ SHObject_Base_Impl(ShadowEngine::Debug::DebugModule) -void ShadowEngine::Debug::DebugModule::Render() { +void ShadowEngine::Debug::DebugModule::OverlayRender() { - ImGui::Begin("Time", &active, ImGuiWindowFlags_MenuBar); - - ImGui::Text("delta time in ms: %lf", Time::deltaTime_ms); - ImGui::Text("delta time in s: %lf", Time::deltaTime); - ImGui::Text("LAST time in: %ld", Time::LAST); + if (ImGui::Begin("Time", &active, ImGuiWindowFlags_MenuBar)) { + ImGui::Text("delta time in ms: %lf", Time::deltaTime_ms); + ImGui::Text("delta time in s: %lf", Time::deltaTime); + ImGui::Text("LAST time in: %d", Time::LAST); + } ImGui::End(); - ImGui::Begin("Active Modules", &active, ImGuiWindowFlags_MenuBar); + if (ImGui::Begin("Active Modules", &active, ImGuiWindowFlags_MenuBar)) { - ShadowEngine::ModuleManager* m = ShadowEngine::ModuleManager::instance; + ShadowEngine::ModuleManager *m = ShadowEngine::ModuleManager::instance; - - - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.4f, 1.0f), "Active Modules:"); - for (auto& module : m->modules) - { - ImGui::Text("%s", module.module->GetName().c_str()); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.4f, 1.0f), "Active Modules:"); + for (auto &module: m->modules) { + ImGui::Text("%s", module.module->GetName().c_str()); + } } - ImGui::End(); } diff --git a/projs/shadow/shadow-engine/shadow-file-format/src/SFFParser.cpp b/projs/shadow/shadow-engine/shadow-file-format/src/SFFParser.cpp index ba5a3fe..67ce66a 100644 --- a/projs/shadow/shadow-engine/shadow-file-format/src/SFFParser.cpp +++ b/projs/shadow/shadow-engine/shadow-file-format/src/SFFParser.cpp @@ -1,5 +1,5 @@ #include "SFFParser.h" -#include "../../shadow-utility/src/string-helpers.h" +#include "string-helpers.h" #include diff --git a/projs/shadow/shadow-engine/shadow-file-format/test/Catch2Test.cpp b/projs/shadow/shadow-engine/shadow-file-format/test/Catch2Test.cpp index 6592347..11727ed 100644 --- a/projs/shadow/shadow-engine/shadow-file-format/test/Catch2Test.cpp +++ b/projs/shadow/shadow-engine/shadow-file-format/test/Catch2Test.cpp @@ -1,5 +1,5 @@ #define CATCH_CONFIG_MAIN -#include +#include "catch2/catch.hpp" TEST_CASE("15 is less than 20", "[numbers]") { REQUIRE(15 < 20); diff --git a/projs/shadow/shadow-engine/shadow-reflection/inc/SHObject.h b/projs/shadow/shadow-engine/shadow-reflection/inc/SHObject.h index c61f30e..7471761 100644 --- a/projs/shadow/shadow-engine/shadow-reflection/inc/SHObject.h +++ b/projs/shadow/shadow-engine/shadow-reflection/inc/SHObject.h @@ -25,7 +25,7 @@ namespace ShadowEngine { * \brief Generates a new UID for each call * \return the next Unique ID that was just generated */ - SH_EXPORT static uint64_t GenerateId() noexcept; + API static uint64_t GenerateId() noexcept; public: /** diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/temp/README.txt b/projs/shadow/shadow-engine/shadow-renderer/inc/temp/README.txt new file mode 100644 index 0000000..568348a --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/temp/README.txt @@ -0,0 +1,37 @@ + +===== + +This folder exists to store VLKX renderer objects that are TEMPORARY. +It currently contains: + +===== + +Model Loader system + +The Model Loader is temporarily implemented as a raw file reader and OBJ parser. +It should be removed when the File Format system is able to parse model and texture files. + +==== + +Model Abstraction system + +The Model Abstraction allows you to create a model with: + - A mesh + - An arbitrary number of textures + - A push constant + - An arbitrarily large uniform buffer + - A fragment and vertex shader + +In all, it contains a custom Render Pipeline that will be used to draw the model. +This allows for drastic and visually appealing effects. + +It should be maintained and moved into the appropriate Shadow module once ready. + +==== + +Model Builder system + +The model Builder allows for simple construction of Models using the Model Abstraction system above. +It consumes the Model Loader and returns a Model Abstraction. + +It should be MOVED into the File Format parsing system once it is ready. \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/temp/model/Builder.h b/projs/shadow/shadow-engine/shadow-renderer/inc/temp/model/Builder.h new file mode 100644 index 0000000..a82c9c0 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/temp/model/Builder.h @@ -0,0 +1,137 @@ +#pragma once + +#include "vlkx/render/shader/Pipeline.h" +#include "Loader.h" +#include "vlkx/render/render_pass/GenericRenderPass.h" +#include "vlkx/vulkan/abstraction/Descriptor.h" + +namespace vlkxtemp { + + class Model; + + class ModelBuilder { + public: + + using ShaderPool = vlkx::ShaderModule::ReleasePool; + using TextureType = ModelLoader::TextureType; + using TexturePerMesh = std::array>, static_cast(TextureType::Count)>; + using BindingPoints = std::map; + using TextureSource = vlkx::RefCountedTexture::ImageLocation; + using TextureSources = std::map>; + + class ModelResource { + public: + virtual ~ModelResource() = default; + virtual void load(ModelBuilder* builder) const = 0; + }; + + class SingleMeshModel : public ModelResource { + public: + SingleMeshModel(std::string&& path, int indexBase, TextureSources&& sources) + : objFile(std::move(path)), objIndexBase(indexBase), textureSources(std::move(sources)) {} + + void load(ModelBuilder* builder) const override; + private: + const std::string objFile; + const int objIndexBase; + const TextureSources textureSources; + }; + + class MultiMeshModel : public ModelResource { + public: + MultiMeshModel(std::string&& modelDir, std::string&& textureDir) + : models(std::move(modelDir)), textures(std::move(textureDir)) {} + + void load(ModelBuilder* builder) const override; + + private: + const std::string models; + const std::string textures; + }; + + struct ModelPushConstant { + struct Meta { + const vlkx::PushConstant* constants; + uint32_t offset; + }; + + VkShaderStageFlags stage; + std::vector constants; + }; + + using Descriptors = std::vector>; + + ModelBuilder(std::string&& name, int frames, float aspect, const ModelResource& resource); + + ModelBuilder(const ModelBuilder&) = delete; + ModelBuilder& operator=(const ModelBuilder&) = delete; + + ModelBuilder& texture(TextureType type, const TextureSource& source); + ModelBuilder& bindTextures(TextureType type, uint32_t point); + ModelBuilder& instanceBuffer(vlkx::PerInstanceVertexBuffer* buffer); + ModelBuilder& uniform(VkShaderStageFlags stage, std::vector&& bindings); + ModelBuilder& uniformBuffer(uint32_t point, const vlkx::UniformBuffer& buffer); + ModelBuilder& pushStage(VkShaderStageFlags stage); + ModelBuilder& pushConstant(const vlkx::PushConstant* constant, uint32_t offset); + ModelBuilder& shader(VkShaderStageFlagBits stage, std::string&& file); + + std::unique_ptr build(); + + private: + std::vector createDescs() const; + + const int frames; + const float aspectRatio; + + std::unique_ptr vertexBuffer; + std::vector textures; + TexturePerMesh sharedTextures; + BindingPoints bindPoints; + + std::vector instanceBuffers; + std::vector uniformMeta; + std::vector uniformBufferMeta; + + std::optional pushConstants; + std::unique_ptr pipelineBuilder; + }; + + class Model { + public: + + Model(const Model&) = delete; + Model& operator=(const Model&) = delete; + + void update(bool opaque, const VkExtent2D& frame, VkSampleCountFlagBits samples, const vlkx::RenderPass& pass, uint32_t subpass, bool flipY = true); + void draw(const VkCommandBuffer& commands, int frame, uint32_t instances) const; + + private: + friend std::unique_ptr ModelBuilder::build(); + using Descriptors = ModelBuilder::Descriptors; + using ModelPushConstant = ModelBuilder::ModelPushConstant; + using TexturePerMesh = ModelBuilder::TexturePerMesh; + + Model(float aspectRatio, + std::unique_ptr&& vertexBuffer, + std::vector&& perInstanceBuffers, + std::optional&& pushConstants, + TexturePerMesh&& sharedTextures, + std::vector&& textures, + std::vector&& descriptors, + std::unique_ptr&& pipelineBuilder) + : aspectRatio(aspectRatio), vertexBuffer(std::move(vertexBuffer)), perInstanceBuffers(std::move(perInstanceBuffers)), + pushConstants(std::move(pushConstants)), sharedTextures(std::move(sharedTextures)), textures(std::move(textures)), + descriptors(std::move(descriptors)), pipelineBuilder(std::move(pipelineBuilder)) {} + + const float aspectRatio; + const std::unique_ptr vertexBuffer; + const std::vector perInstanceBuffers; + const std::optional pushConstants; + const TexturePerMesh sharedTextures; + const std::vector textures; + const std::vector descriptors; + + std::unique_ptr pipelineBuilder; + std::unique_ptr pipeline; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/temp/model/Loader.h b/projs/shadow/shadow-engine/shadow-renderer/inc/temp/model/Loader.h new file mode 100644 index 0000000..9cbe90f --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/temp/model/Loader.h @@ -0,0 +1,57 @@ +#pragma once +#include +#include +#include "vlkx/render/Geometry.h" + +namespace vlkxtemp { + + struct Wavefront { + Wavefront(std::string_view path, size_t base); + Wavefront(const Wavefront&) = delete; + + Wavefront& operator=(const Wavefront&) = delete; + + std::vector indices; + std::vector vertices; + }; + + class ModelLoader { + public: + enum class TextureType { + Diffuse, + Specular, + Reflection, + Cubemap, + Count + }; + + struct TextureData { + TextureData(TextureData&&) noexcept = default; + TextureData& operator=(TextureData&&) noexcept = default; + + std::string path; + TextureType type; + }; + + struct MeshData { + MeshData() = default; + MeshData(MeshData&&) noexcept = default; + MeshData& operator=(MeshData&&) noexcept = default; + + std::vector vertices; + std::vector indices; + std::vector textures; + }; + + ModelLoader(const std::string& model, const std::string& textures); + + ModelLoader(const ModelLoader&) = delete; + ModelLoader& operator=(const ModelLoader&) = delete; + + const std::vector& getMeshes() const { return meshes; } + + private: + + std::vector meshes; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/Camera.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/Camera.h index 5511f72..9684718 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/Camera.h +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/Camera.h @@ -1,23 +1,213 @@ #pragma once +#include #define GLM_FORCE_RADIAN #include #include +#include -class Camera { -public: +namespace vlkx { + class Camera { + public: - // Set up the camera. - void init(float fov, float width, float height, float near, float far); + enum class Input { + Up, Down, Left, Right + }; + struct Movement { + float moveSpeed = 10; + float turnSpeed = 0.0005f; + std::optional center; + }; - // Move the camera. - void setPosition(glm::vec3 positionIn); + /** + * Camera configuration; with defaults. + * Left and forward vectors are calculated from up, pos and target. + */ + struct Config { + float nearPlane = 0.1f; // The nearest a vertex can be to the camera before being clipped + float farPlane = 100; // The furthest a vertex can be from the camera before clipped + glm::vec3 upV{0, 1, 0}; // The vector pointing straight up from the camera + glm::vec3 pos{0, 0, 0}; // The position of the camera in the world + glm::vec3 target{1, 0, 0}; // The point the camera is looking at + }; - glm::mat4 getViewMatrix() { return viewMatrix; }; - glm::mat4 getProjectionMatrix() { return projectionMatrix; } + Camera(const Camera &) = delete; -private: - glm::mat4 projectionMatrix; - glm::mat4 viewMatrix; - glm::vec3 position; -}; \ No newline at end of file + Camera &operator=(const Camera &) = delete; + + virtual ~Camera() = default; + + Camera &move(const glm::vec3 &delta); + + Camera &setPos(const glm::vec3 &pos); + + Camera &up(const glm::vec3 &up); + + Camera &forward(const glm::vec3 &forward); + + glm::mat4 getViewMatrix() const; + + glm::mat4 getSkyboxView() const { + return glm::mat4{glm::mat3{getViewMatrix()}}; + } + + virtual glm::mat4 getProjMatrix() const = 0; + + const glm::vec3& getPosition() const { return position; } + const glm::vec3& getUp() const { return upVector; } + const glm::vec3& getForward() const { return frontVector; } + const glm::vec3& getRight() const { return rightVector; } + + protected: + explicit Camera(const Config &conf) : nearPlane(conf.nearPlane), farPlane(conf.farPlane), position(conf.pos), + upVector(glm::normalize(conf.upV)) { + forward(conf.target - position); + } + + const float nearPlane; + const float farPlane; + private: + + glm::vec3 position; + glm::vec3 upVector; + glm::vec3 frontVector; + glm::vec3 rightVector; + + }; + + class PerspectiveCamera : public Camera { + public: + + struct Frustum { + float fov; + float aspect; + }; + + struct RT { + glm::vec3 up; + glm::vec3 forward; + glm::vec3 right; + }; + + PerspectiveCamera(const Camera::Config &conf, const Frustum &frus) : + Camera(conf), aspectRatio(frus.aspect), fov(frus.fov) {} + + PerspectiveCamera(const PerspectiveCamera &) = delete; + + PerspectiveCamera &operator=(const PerspectiveCamera &) = delete; + + PerspectiveCamera &fieldOfView(float newFov); + + RT getRT() const; + + glm::mat4 getProjMatrix() const override; + + float getFieldOfView() const { return fov; } + + float getAspect() const { return aspectRatio; } + + private: + + const float aspectRatio; + float fov; + }; + + class OrthographicCamera : public Camera { + public: + struct OrthoConfig { + float width; + float aspect; + }; + + static OrthoConfig getFullscreenConfig() { + return {2, 1}; + } + + OrthographicCamera(const Camera::Config &config, const OrthoConfig &ortho) + : Camera(config), aspectRatio(ortho.aspect), width(ortho.width) {} + + OrthographicCamera(const OrthographicCamera &) = delete; + + OrthographicCamera &operator=(const OrthographicCamera &) = delete; + + OrthographicCamera &setWidth(float width); + + glm::mat4 getProjMatrix() const override; + + float getWidth() const { return width; } + + private: + + const float aspectRatio; + float width; + }; + + template + class UserCamera { + public: + UserCamera(const UserCamera &) = delete; + + UserCamera &operator=(const UserCamera &) = delete; + + virtual ~UserCamera() = default; + + void setInternal(std::function op); + + void setPos(const glm::dvec2 &pos) { cursorPos = pos; } + + void move(double x, double y); + + bool scroll(double delta, double min, double max); + + void press(Camera::Input key, float time); + + void active(bool active) { isActive = active; } + + const Type &getCamera() const { return *camera; } + + UserCamera(const Camera::Movement &movement, std::unique_ptr &&cam) + : config(movement), camera(std::move(cam)) { + reset(); + } + + void reset(); + + private: + + + const Camera::Movement config; + bool isActive = false; + + std::unique_ptr camera; + glm::dvec2 cursorPos; + glm::vec3 refForward; + glm::vec3 refLeft; + + float pitch; + float yaw; + }; + + class UserPerspectiveCamera : public UserCamera { + public: + static std::unique_ptr + create(const Camera::Movement &movement, const Camera::Config &config, + const PerspectiveCamera::Frustum &frustum) { + return std::make_unique(movement, + std::make_unique(config, frustum)); + } + + protected: + using UserCamera::UserCamera; + }; + + class UserOrthoCamera : public UserCamera { + public: + static std::unique_ptr create(const Camera::Movement &movement, const Camera::Config &config, + const OrthographicCamera::OrthoConfig &ortho) { + return std::make_unique(movement, std::make_unique(config, ortho)); + } + + protected: + using UserCamera::UserCamera; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/Geometry.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/Geometry.h index cce60c1..d208974 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/Geometry.h +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/Geometry.h @@ -28,65 +28,66 @@ namespace Geo { }; // All of the metadata involved with a vertex. - struct Vertex { + struct VertexAll { glm::vec3 position; // XYZ coordinates of the vertex's position. glm::vec3 normal; // Unit vector pointing away from the outer surface of the vertex. - glm::vec3 color; // The color of the vertex. glm::vec2 texture; // The u/v coordinates of this vertex in the bound texture. // How fast should vertex data be read from RAM? static VkVertexInputBindingDescription getBindingDesc() { VkVertexInputBindingDescription desc = {}; desc.binding = 0; - desc.stride = sizeof(Vertex); + desc.stride = sizeof(VertexAll); desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; return desc; } // How should vertexes be handled? - static std::array getAttributeDesc() { - std::array descs = {}; - - // Attribute 0; position. Location 0, 3x 32-bit float. - descs[0].binding = 0; - descs[0].location = 0; - descs[0].format = VK_FORMAT_R32G32B32_SFLOAT; - descs[0].offset = offsetof(Vertex, position); - - // Attribute 1; normal. Location 1, 3x 32-bit float. - descs[1].binding = 0; - descs[1].location = 1; - descs[1].format = VK_FORMAT_R32G32B32_SFLOAT; - descs[1].offset = offsetof(Vertex, normal); - - // Attribute 2; color. Location 2, 3x 32-bit float. - descs[2].binding = 0; - descs[2].location = 2; - descs[2].format = VK_FORMAT_R32G32B32_SFLOAT; - descs[2].offset = offsetof(Vertex, color); - - // Attribute 3; texture. Location 3, 2x 32-bit float. - descs[3].binding = 0; - descs[3].location = 3; - descs[3].format = VK_FORMAT_R32G32_SFLOAT; - descs[3].offset = offsetof(Vertex, texture); - - return descs; + static std::vector getAttributeDesc() { + return { + { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexAll, position)) }, + { 0, 1, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexAll, normal)) }, + { 0, 2, VK_FORMAT_R32G32_SFLOAT, static_cast(offsetof(VertexAll, texture)) } + }; } }; + // All of the metadata involved with a vertex. + struct VertexColor { + glm::vec3 position; // XYZ coordinates of the vertex's position. + glm::vec3 color; // The color of the vertex. + + // How fast should vertex data be read from RAM? + static VkVertexInputBindingDescription getBindingDesc() { + VkVertexInputBindingDescription desc = {}; + desc.binding = 0; + desc.stride = sizeof(VertexColor); + desc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + return desc; + } + + // How should vertexes be handled? + static std::vector getAttributeDesc() { + return { + { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexColor, position)) }, + { 0, 1, VK_FORMAT_R32G32B32_SFLOAT, static_cast(offsetof(VertexColor, color)) } + }; + } + }; + // Contains data about a given Mesh. class Mesh { public: // Pre-load the data for a triangle into the given buffers. - static void setTriData(std::vector& vertices, std::vector& indices); + static void setTriData(std::vector& vertices, std::vector& indices); // Pre-load the data for a quad into the given buffers. - static void setQuadData(std::vector& vertices, std::vector& indices); + static void setQuadData(std::vector& vertices, std::vector& indices); // Pre-load the data for a cube into the given buffers. - static void setCubeData(std::vector& vertices, std::vector& indices); + static void setCubeData(std::vector& vertices, std::vector& indices); // Pre-load the data for a sphere into the given buffers. - static void setSphereData(std::vector& vertices, std::vector& indices); + static void setSphereData(std::vector& vertices, std::vector& indices); }; diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/framebuffer/RenderPass.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/framebuffer/RenderPass.h deleted file mode 100644 index 129bc39..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/framebuffer/RenderPass.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include - -class RenderPass { -public: - RenderPass(); - ~RenderPass(); - - VkRenderPass pass; - - void createVertexRenderPass(VkFormat format); - void createRTRenderPass(VkFormat format); - void createRTPhysicsPass(VkFormat format); - - void beginRenderPass(std::vector clearValues, VkCommandBuffer commands, VkFramebuffer framebuffer, VkExtent2D extent); - void endRenderPass(VkCommandBuffer commands); - - void destroy(); -}; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/geometry/SingleRenderer.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/geometry/SingleRenderer.h deleted file mode 100644 index d867548..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/geometry/SingleRenderer.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// Renders a single object. -class SingleRenderer { -public: - - void createSingleRenderer(Geo::MeshType type, glm::vec3 posIn, glm::vec3 scaleIn); - - void updateUniforms(Camera camera); - - void draw(); - - void destroy(); - - void setPosition(glm::vec3 newPos) { position = newPos; } - void setRotation(glm::mat4 newRot) { rotation = newRot; } - - Descriptor getDescriptor() { return descriptor; } - - glm::mat4 getRotation() { return rotation; } -private: - - Pipeline pipeline; - GeoBuffers buffers; - Descriptor descriptor; - - glm::vec3 position; - glm::vec3 scale; - glm::mat4 rotation; -}; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/GPUPass.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/GPUPass.h new file mode 100644 index 0000000..87ea9f5 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/GPUPass.h @@ -0,0 +1,242 @@ +#pragma once + +#include +#include "vlkx/vulkan/abstraction/ImageUsage.h" +#include +#include +#include +#include "GenericRenderPass.h" + +namespace vlkx { + + /** + * The common base class for rendering and computing passes that run on the GPU. + * Provides some utility methods for handling attachment metadata between subpasses. + */ + class CommonPass { + public: + + explicit CommonPass(int passes) : numPasses(passes) {} + + // Delete the copy and move constructors + CommonPass(const CommonPass&) = delete; + CommonPass& operator=(const CommonPass&) = delete; + virtual ~CommonPass() = default; + + // Get the image layout of the given image at the start of this pass + VkImageLayout getInitialLayout(const std::string& name) const; + // Get the image layout of the given image at the end of this pass + VkImageLayout getFinalLayout(const std::string& name) const; + // Get the image layout of the given image before the given subpass starts + VkImageLayout getSubpassLayout(const std::string& name, int subpass) const; + + // Update the state of the given image's usage tracker. + void update(const std::string& name, MultiImageTracker& tracker) const; + + protected: + /** + * Some metadata about the usage of an image between subpasses. + */ + struct Usages { + Usages(const int last, const ImageUsage* prev, const ImageUsage* curr) : lastSubpass(last), lastUsage(*prev), currentUsage(*curr) {} + const int lastSubpass; + const ImageUsage& lastUsage; + const ImageUsage& currentUsage; + }; + + // Add the usage of an image in the pass to its' tracker. + void addUsage(std::string&& name, UsageTracker&& tracker); + + // Get the full history of the image's usages up to this rendering pass. + const UsageTracker& getHistory(const std::string& name) const; + + // Get the usage of an image at the start of the given pass. + const ImageUsage* getUsage(const std::string& name, int pass) const; + + // Retrieve image usage data, but only if the image is barriered at the given pass. + std::optional checkForSync(const std::string& name, int pass) const; + + // Validate that the subpass is valid for the given image. + // The meaning of includeVirtual is defined by the child implementation. + void validate(int pass, const std::string& image, bool includeVirtual) const; + + int getVirtualInitial() const { return -1; } + int getVirtualFinal() const { return numPasses; } + + protected: + std::map usageHistory; + const int numPasses; + }; + + /** + * The Common Pass implementation for Graphics passes; that is, render passes that output to color buffers + * for presentation to the screen, or to be used as textures in such. + * The instance of the GraphicsPass can be stored and reused to create multiple RenderPassBuilders. + * In this way it is essentially a RenderPassBuilderFactory. + */ + class GraphicsPass : public CommonPass { + public: + + using LocationGetter = std::function; + + explicit GraphicsPass(int passes) : CommonPass {passes} {} + + GraphicsPass(const GraphicsPass&) = delete; + GraphicsPass& operator=(const GraphicsPass&) = delete; + + // Get the default render ops for a color buffer. + static RenderPassBuilder::Attachment::OpsType getDefaultOps() { + return RenderPassBuilder::Attachment::ColorOps { VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE }; + } + + // Get the default render ops for a stencil buffer. + static RenderPassBuilder::Attachment::OpsType getStencilOps() { + return RenderPassBuilder::Attachment::StencilDepthOps { VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_DONT_CARE }; + } + + /** + * Add an image reference that is used in this render pass. + * @param name the name of the image used + * @param history the usage history of the image, for tracking purposes + * @param getter a function to get the location of the image, only if the image is used as a render target. + * @param ops optional; uses the static defaults if not present. + * @return the index into the VkAttachmentDescriptions. + */ + int add(const std::string& name, UsageTracker&& history, LocationGetter&& getter, const std::optional ops = std::nullopt); + + #define fluent GraphicsPass& + + // Specifies that the source image will be resolved to the single destination at the given pass. + fluent addMultisample(const std::string& source, const std::string& dest, int pass); + + // Build a RenderPassBuilder with the information provided so far. + std::unique_ptr build(int framebuffers); + + private: + struct AttachmentMeta { + int index; + LocationGetter getter; + vlkx::RenderPassBuilder::Attachment::OpsType ops; + std::map multisample; + }; + + void setAttachments(); + void setSubpasses(); + void setDependencies(); + + /** + * Find the first subpass where the given image is used as a render target. + * @param history the usage history of the image; what it was used at at each subpass. + * @return nullopt if the image was not used as a render target, the index of the subpass where it was, if not. + */ + std::optional getFirstRenderTarget(const UsageTracker& history) const; + + /** + * Return the operations that should be used for the given image attachment. + * If the user specified ops, it will be checekd against the history. + * @param name the name of the image to use as the attachment + * @param history the usage history of the attachment, for internal checks + * @param userOps operations to use for the image, as an optional override. + * @return the ColorOps to use for the given attachment. + */ + RenderPassBuilder::Attachment::OpsType getOps(const std::string& name, const UsageTracker& history, const std::optional& userOps) const; + + /** + * Get the usage type of the image. + * Assumption: an image is only ever used as a color OR depth stencil. Never both. + * Assumption: Multisample == RenderTarget + * @param name the name of the image to check + * @param history the history of the image's usages in the GPU. + * @return whether the image is a RenderTarget or a DepthStencil buffer. + */ + ImageUsage::Type getUsageType(const std::string& name, const UsageTracker& history) const; + + /** + * Ensure that the image is used as type at subpass in its' history. + */ + bool verifyImageUsage(const UsageTracker& history, int subpass, ImageUsage::Type type) const; + + /** + * Return whether the subpass is virtual. + * For a Render Pass, virtual means it is a preprocessing step. + */ + bool isVirtual(int subpass) const { + return subpass == getVirtualInitial() || subpass == getVirtualFinal(); + } + + /** + * Return the subpass index; for virtual passes, it uses an EXTERNAL subpass. + */ + uint32_t checkSubpass(int subpass) const { + return isVirtual(subpass) ? VK_SUBPASS_EXTERNAL : (uint32_t) subpass; + } + + /** + * Ensure that the image's usages are compatible with a render pass. + * For example, compute shader linear buffers cannot be used as render targets, etc. + */ + void verifyHistory(const std::string& image, const UsageTracker& history) const; + + std::map metas; + std::unique_ptr builder; + + }; + + + /** + * The Common Pass implementation for Compute Shaders. + * That is, shaders that do not write to color buffers. + * A subpass can execute multiple compute shaders unbarriered, which increases efficiency. + * We still need to transition images between passes when necessary, hence the wrapper. + */ + class ComputePass : public CommonPass { + public: + + ComputePass(const ComputePass&) = delete; + ComputePass& operator=(const ComputePass&) = delete; + + #define fluent ComputePass& + + /** + * Add the given image as an attachment to the compute shader pass. + * @param name the name of the image + * @param history the usage history of the image + * @return the ComputePass instance, for chaining. + */ + fluent add(std::string&& name, UsageTracker&& history); + fluent add(const std::string& name, UsageTracker&& history) { + return add(std::string(name), std::move(history)); + } + + /** + * Run computeOps, insert memory barriers to transition used images into the appropriate format. + * Images must be a superset of all images that were called with add(). + * Compute_ops must be equal to the number of subpasses. + * Commands must be recording. + * @param commands the command buffer to write into. + * @param queueFamily the family to use for inserting barriers + * @param images the list of images that were used in the compute pass + * @param computeOps the compute functions to upload to the GPU + */ + void execute(const VkCommandBuffer& commands, uint32_t queueFamily, const std::map& images, const std::vector>& computeOps) const; + + /** + * Insert a memory barrier, to transition the layout of the image from the previous to the curent. + * The barrier is performed using the given queue family. + * @param commands the command buffer to write into. + * @param queueFamily the family to use for inserting barriers. + * @param image the list of images that were used in the compute pass + * @param prev the previous usage of the image; the state being transitioned from + * @param current the new usage of the image; the state being transitioned to. + */ + void barrier(const VkCommandBuffer& commands, uint32_t queueFamily, const VkImage& image, const ImageUsage& prev, const ImageUsage& current) const; + + /** + * Verify whether the previous usages of the given image in its' history is compatible with a compute shader. + * For example, a fragment shader output image is not compatible. + * @param name the name of the image being checked + * @param history the usage history of the image/ + */ + void verify(const std::string& name, const UsageTracker& history) const; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/GenericRenderPass.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/GenericRenderPass.h new file mode 100644 index 0000000..37764e6 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/GenericRenderPass.h @@ -0,0 +1,238 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "vlkx/vulkan/Tools.h" +#include "vlkx/vulkan/abstraction/Image.h" + +namespace vlkx { + + /** + * Gathers the operations that the GPU should perform when rendering to a framebuffer. + * Subpasses and dependencies are to be configured automatically using the builder below. + * RenderPass objects are disposable, and should be discarded when the framebuffer changes. + */ + class RenderPass { + public: + using RenderFunc = std::function; + + // Delete copy and move constructors to prevent the GPU getting confused with what we're trying to do + RenderPass(const RenderPass&) = delete; + RenderPass& operator=(const RenderPass&) = delete; + ~RenderPass(); + + RenderPass(int subpasses, VkRenderPass pass, std::vector clear, VkExtent2D ext, std::vector fbs, std::vector attachs) + : subpassCount(subpasses), renderPass(pass), clearValues(std::move(clear)), extent(ext), framebuffers(std::move(fbs)), attachments(std::move(attachs)) {} + + const VkRenderPass& operator*() const { return renderPass; } + + int getAttachsInSubpass(int subpass) const { + return attachments[subpass]; + } + + /** + * Upload all of the subpass render commands to the command buffer. + * The size of ops must be equal to the number of subpasses in this render pass. + * @param commands the command buffer to execute on; must be recording + * @param imageIndex the index of the image on the swapchain that we're rendering to; the target framebuffer. + * @param ops the render operations to add onto the command buffer. + */ + void execute(const VkCommandBuffer& commands, int imageIndex, std::vector ops) const; + + private: + // The number of sub-render-passes in this pass. + const int subpassCount; + // The VkRenderPass that this class wraps. + VkRenderPass renderPass; + // The clear values that will wipe all framebuffers to their empty states. + const std::vector clearValues; + // The size of the framebuffers (all are the same size) + const VkExtent2D extent; + // The framebuffers that we can render to + const std::vector framebuffers; + // The number of color attachments (sampled color images) in each subpass, by subpass index. + const std::vector attachments; + }; + + /** + * A stateful, fluent way to create Render Passes. + * This object can be stored and reused; when the window size changes, simply set the extent and + * export a new RenderPass to be used in the pipeline. + * + * Allows setting sub-passes, sub-pass dependencies, operations to read and write them, etc. + */ + class RenderPassBuilder { + public: + + /** + * Information required to define an attachment to be used in a render pass. + * Contains information on the layout, the operations to use on read and write, etc. + */ + struct Attachment { + // Operations to use on color attachments. + struct ColorOps { + VkAttachmentLoadOp LOAD; // Load data in the color attachment + VkAttachmentStoreOp STORE; // Store data into the color attachment + }; + + // Operations to use on depth and stencil buffers. + struct StencilDepthOps { + VkAttachmentLoadOp DEPTH_LOAD; // Load data in the depth attachment + VkAttachmentStoreOp DEPTH_STORE; // Store data in the depth attachment + VkAttachmentLoadOp STENCIL_LOAD; // Load data in the stencil attachment + VkAttachmentStoreOp STENCIL_STORE; // Store data in the stencil attachment + }; + + using OpsType = std::variant; + + // The operations that can be performed on this attachment + OpsType ops; + // The initial layout of an image in this attachment (pre-GPU upload) + VkImageLayout layoutInitial; + // The final layout of an image in this attachment (as seen by the shader) + VkImageLayout layoutFinal; + }; + + /** + * Describes attachments used in each subpass, in terms of Vulkan data. + * Attachment here is used in the conceptual sense, not referring to the Attachment struct above. + * + * If multisampleReferences is non-zero, its' size must be equal to colorReferences' size. + * Each index of multisampleReferences refers to the same-index colorReferences entry. + * + * If stencilDepthReference is non-zero, it is shared between all subpasses. + */ + struct SubpassAttachments { + std::vector colorReferences; + std::vector multisampleReferences; + std::optional stencilDepthReference; + }; + + /** + * Describes the dependencies between each sub-pass. + * It describes how each subpass will read or modify the data written by the last subpass, if at all. + * This dependency information can allow the GPU to run some passes in parallel, and enforce the + * strict ordering of those that require it. + */ + struct SubpassDependency { + + /** + * Defines some metadata about the subpass. + * Contains the index of the subpass, how it will use data from the last pass, and what exactly it will do. + */ + struct SubpassMeta { + /** + * Index of the subpass. + */ + uint32_t index; + + /** + * Describes how we want to modify the data passed to us from the last subpass. + * Will change how the next subpass will wait for the completion of this subpass, if at all. + * + * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT: + * read/write to the color attachment + * + * VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT: + * VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT: + * read/write to the depth or stencil attachment + * + * VK_PIPELINE_STAGE_VERTEX_SHADER_BIT: + * VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT: + * read all attachments + * + */ + VkPipelineStageFlags stage; + + /** + * Describes how we want to synchronize with the subpass after this one. + * + * VK_ACCESS_SHADER_READ_BIT: + * VK_ACCESS_SHADER_WRITE_BIT: + * read a texture or write to a color buffer + * + * VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: + * VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: + * VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: + * VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: + * read/write to an attachment. + * + * VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: + * for accessing the inputAttachment of a subpass. + * + * 0: + * do not write, but the next subpass will. + * Will automatically barrier the render pass. + */ + VkAccessFlags access; + }; + + SubpassMeta source; // The source subpass of this dependency (will take effect after this pass completes) + SubpassMeta destination; // The destination subpass of this dependency (will take effect before this pass) + VkDependencyFlags flags; // Other information that Vulkan needs to know about this dependency; for example, if we use an inputAttachment. + }; + + /** + * Describes a color attachment. + * Effectively RGB images that live entirely on the GPU. + * + * Describes the resolution mechanics of a multisampled image. + */ + struct ColorAttachmentMeta { + int location; // Where the GPU shaders expect this attachment to be available. + int descriptionIdx; // Index of this attachment in the VkAttachmentDescription data. + VkImageLayout layout; // Vulkan image layout. Shader optimized or host readable. + }; + + /** + * Create a list of VkAttachmentReference that describes the attachments used per subpass. + */ + static std::vector parseColorReferences(std::vector meta); + + /** + * Create a list of VkAttachmentReference that describes the multisampling setup. + */ + static std::vector parseMutisampling(int colorReferencesCount, std::vector meta); + + RenderPassBuilder(const RenderPassBuilder&) = delete; + RenderPassBuilder& operator=(const RenderPassBuilder&) = delete; + ~RenderPassBuilder() = default; + RenderPassBuilder() = default; + + /** Fluent API Features; chain calls to set data on the render pass.*/ + #define fluent RenderPassBuilder& + + // Set the number of framebuffers in the render pass + fluent setFramebufferCount(int count); + // Set an attachment description in the render pass + fluent setAttachment(int idx, const Attachment& attachment); + // Update the image backing an attachment. The function must be executable during execute() later on. + fluent updateAttachmentBacking(int idx, std::function&& getBacking); + // Set a specific subpass. Use the static parse methods to create these vectors. + fluent setSubpass(int idx, std::vector&& color, std::vector&& multisample, VkAttachmentReference& depthStencil); + // Add a dependency between two subpasses. + fluent addDependency(const SubpassDependency& dep); + + // Build the Render Pass with all the information given. + // Can be called multiple times with the same Builder. + [[nodiscard]] std::unique_ptr build() const; + + private: + // Number of framebuffers in the render pass + std::optional framebufferCount; + // Descriptions of used attachments + std::vector attachmentDescriptors; + // Functions to return attachment images. + std::vector> attachmentGetters; + // Values to clear all attachments + std::vector clearValues; + // Descriptions of subpasses. + std::vector subpassAttachments; + // Descriptions of subpass dependencies. + std::vector subpassDependencies; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/ScreenRenderPass.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/ScreenRenderPass.h new file mode 100644 index 0000000..d431130 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/render_pass/ScreenRenderPass.h @@ -0,0 +1,130 @@ +#pragma once + +#include +#include +#include "GenericRenderPass.h" +#include "vlkx/vulkan/abstraction/ImageUsage.h" +#include "vlkx/vulkan/abstraction/Image.h" + +namespace vlkx { + + // A simple and versatile way to configure render passes. + // Intended to be used with the SimpleRenderPass and the ScreenRenderPass. + class RendererConfig { + public: + RendererConfig(std::vector>& destinations, bool toScreen = true) : renderImages(destinations) { + numOpaquePasses = 1; + rendersToScreen = toScreen; + } + + RendererConfig(int passCount, std::vector>& destinations, bool toScreen = true, std::optional firstTransparent = std::nullopt, std::optional firstOverlay = std::nullopt); + + // Get the number of passes that use the depth buffer. + int depthPasses() const { + return numOpaquePasses + numTransparentPasses; + } + + // Get the total number of passes. + int passes() const { + return depthPasses() + numOverlayPasses; + } + + // Get whether any passes use the depth buffer. + bool usesDepth() const { + return depthPasses() > 0; + } + + // Create the render pass builder. Can be called multiple times. + void build(); + + RendererConfig(RendererConfig&) noexcept = default; + RendererConfig(const RendererConfig&) = default; + + int numOpaquePasses = 0; + int numTransparentPasses = 0; + std::vector>& renderImages; + bool rendersToScreen; + private: + int numOverlayPasses = 0; + }; + + /** + * Stores all of the information required to use an attachment. + * This is heavy, so is only used when the image is being finalized. + */ + struct AttachmentConfig { + AttachmentConfig(std::string_view name, std::optional* index) + : name(name), index(*index) {} + + AttachmentConfig& setOps(const RenderPassBuilder::Attachment::OpsType& ops) { + loadStoreOps = ops; + return *this; + } + + AttachmentConfig& setUsage(const ImageUsage& final) { + finalUsage = final; + return *this; + } + + std::string name; + std::optional& index; + std::optional loadStoreOps; + std::optional finalUsage; + }; + + /** + * A lighter version of the Attachment, used primarily in the On-Screen Pass Manager. + */ + struct Attachment { + explicit Attachment(std::string_view image) : name(image) {} + + // Adds the image to the tracker and initializes state. + void add(MultiImageTracker& tracker, const Image& image) { + tracker.track(name, image.getUsage()); + } + + AttachmentConfig makeConfig() { return { name, &index }; } + + const std::string name; + std::optional index; + }; + + // Manages Render Passes that will output to the screen. + // This is necessarily exclusively a graphical pass. + // If necessary, a depth and stencil buffer will be maintained. + // The color buffer is automatically assumed to be the swapchain. + class ScreenRenderPassManager { + public: + explicit ScreenRenderPassManager(RendererConfig renderConfig) : config(renderConfig) {} + + ScreenRenderPassManager(const ScreenRenderPassManager&) = delete; + ScreenRenderPassManager& operator=(const ScreenRenderPassManager&) = delete; + + // Initialize the render pass we're managing. + void initializeRenderPass(); + + std::unique_ptr& getPass() { return pass; } + + private: + + // Prepare the Render Pass builder. + void preparePassBuilder(); + + const RendererConfig config; + + Attachment destinationInfo { "Destination" }; + Attachment multisampleInfo { "Multisample" }; + Attachment depthStencilInfo { "Depth-Stencil" }; + + std::unique_ptr depthStencilImage; + std::unique_ptr passBuilder; + std::unique_ptr pass; + }; + + /** + * A utility namespace used to house a constructor for creating a "simple" render pass with all the defaults. + */ + namespace SimpleRenderPass { + static std::unique_ptr createBuilder(int framebuffers, const RendererConfig& config, const AttachmentConfig& color, const AttachmentConfig* multisample, const AttachmentConfig* depthStencil, MultiImageTracker& tracker); + } +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/Descriptor.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/Descriptor.h deleted file mode 100644 index 88d70f3..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/Descriptor.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include - -class Descriptor { -public: - Descriptor(); - ~Descriptor(); - - // Global descriptor bindings - VkDescriptorSetLayout layout; - VkDescriptorPool pool; - VkDescriptorSet set; - - // Allocate and prepare the descriptors for a simple (uniform buffer only) descriptor. - void createAndAllocateSimple(uint32_t imageCount); - - // Fill the Descriptors with the given uniforms - void populate(uint32_t imageCount, VkBuffer uniforms, size_t bufferSize); - void destroy(); - -private: - - // Set up the layout for a single UBO - void createSimpleLayout(); - // Setup the pool for a single UBO - void createSimplePool(uint32_t imageCount); - -}; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/GeoBuffers.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/GeoBuffers.h deleted file mode 100644 index e527e80..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/GeoBuffers.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -// Contains memory and objects required to store information about geometry. -class GeoBuffers { -public: - - GeoBuffers(); - ~GeoBuffers(); - - // Program and virtual memory for vertex data. - std::vector vertices; - VkTools::ManagedBuffer vertexBuffer; - - // Program and virtual memory for indices data. - std::vector indices; - VkTools::ManagedBuffer indexBuffer; - - // Virtual memory for uniforms - translation matrices, etc. - VkTools::ManagedBuffer uniformBuffer; - - void createBuffers(Geo::MeshType type); - - void destroy(); - -private: - - void createVertexBuffer(); - void createIndexBuffer(); - void createUniformBuffer(); - -}; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/Pipeline.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/Pipeline.h index eee2fb7..569f087 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/Pipeline.h +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/shader/Pipeline.h @@ -1,31 +1,205 @@ #pragma once #include #include +#include #include +#include "shadow/util/RefCounter.h" +#include "vlkx/vulkan/VulkanModule.h" -class Pipeline { -public: - Pipeline(); - ~Pipeline(); +namespace vlkx { + class Pipeline; - // The active Graphics Pipeline layout. - VkPipelineLayout layout; - // The active Graphics Pipeline instance. - VkPipeline pipeline; + // A simple wrapper for the shader module used by the pipeline. + class ShaderModule { + public: + using CountedShader = shadowutil::RefCounter; + using ReleasePool = CountedShader::AutoRelease; - // Create the layout and pipeline for a vertex renderer - void create(VkExtent2D extent, VkDescriptorSetLayout set, VkRenderPass renderPass); + ShaderModule(const std::string& path); - void destroy(); + ShaderModule(const ShaderModule&) = delete; + ShaderModule& operator=(const ShaderModule&) = delete; -private: + ~ShaderModule() { + vkDestroyShaderModule(VulkanModule::getInstance()->getDevice()->logical, shader, nullptr); + } - std::vector readFile(const std::string& filename); - VkShaderModule createShaderModule(const std::vector& code); + const VkShaderModule& operator*() const { return shader; } - void createPipelineLayout(VkDescriptorSetLayout set); - - // For rendering objects that use traditional vertex-based mesh geometry. - // See Geo::Vertex for the uniform bindings. - void createVertexPipeline(VkExtent2D extent, VkRenderPass renderPass); -}; \ No newline at end of file + private: + VkShaderModule shader; + }; + + class PipelineBuilder { + public: + PipelineBuilder(const PipelineBuilder&) = delete; + PipelineBuilder& operator=(const PipelineBuilder&) = delete; + + virtual ~PipelineBuilder() { + vkDestroyPipelineCache(VulkanModule::getInstance()->getDevice()->logical, cache, nullptr); + } + + virtual std::unique_ptr build() const = 0; + + protected: + PipelineBuilder(std::optional maxCache); + + void setName(std::string&& n) { name = std::move(name); } + + void setLayout(std::vector&& descLayouts, std::vector&& constants); + + const std::string& getName() const { return name; } + + bool hasLayout() const { return layoutInfo.has_value(); } + const VkPipelineLayoutCreateInfo& getLayout() const { return layoutInfo.value(); } + + private: + VkPipelineCache cache; + std::string name; + + std::optional layoutInfo; + std::vector descLayouts; + std::vector constants; + }; + + /** + * Use when creating Graphics pipelines. + * Internal state is preserved so that multiple pipelines can be created with one builder. + * However, shaders are single-usage. Bind a new shader before claling build again. + * See ShaderModule for more information, and how to change this. + */ + class GraphicsPipelineBuilder : public PipelineBuilder { + public: + struct Viewport { + VkViewport viewport; + VkRect2D scissor; + }; + + explicit GraphicsPipelineBuilder(std::optional maxCache = std::nullopt); + + GraphicsPipelineBuilder(const GraphicsPipelineBuilder&) = delete; + GraphicsPipelineBuilder& operator=(const GraphicsPipelineBuilder&) = delete; + + #define fluent GraphicsPipelineBuilder& + + fluent name(std::string&& name); + fluent depthTest(bool enable, bool write); + fluent stencilTest(bool enable); + fluent multiSample(VkSampleCountFlagBits samples); + fluent topology(VkPrimitiveTopology topology); + fluent stencilOp(const VkStencilOpState& state, VkStencilFaceFlags flags); + + fluent addVertex(uint32_t bindPoint, VkVertexInputBindingDescription&& desc, std::vector&& attrs); + fluent layout(std::vector&& descLayouts, std::vector&& constants); + fluent viewport(const Viewport& port, bool flipY = true); + fluent renderPass(const VkRenderPass& pass, uint32_t subpass); + + fluent colorBlend(std::vector&& states); + fluent shader(VkShaderStageFlagBits stage, std::string&& file); + + std::unique_ptr build() const override; + + private: + struct PassInfo { + VkRenderPass pass; + uint32_t subpass; + }; + + VkPipelineInputAssemblyStateCreateInfo assemblyInfo; + VkPipelineRasterizationStateCreateInfo rasterizationInfo; + VkPipelineMultisampleStateCreateInfo multisampleInfo; + VkPipelineDepthStencilStateCreateInfo depthStencilInfo; + VkPipelineDynamicStateCreateInfo dynamicStateInfo; + + std::vector bindingDescs; + std::vector attrDescs; + + std::optional viewportMeta; + std::optional passMeta; + std::vector blendStates; + std::map shaders; + }; + + /** + * Use when creating Compute Shader pipelines. + * Internal state is preserved so that multiple pipelines can be created with one builder. + * However, shaders are single-usage. Bind a new shader before claling build again. + * See ShaderModule for more information, and how to change this. + */ + class ComputePipelineBuilder : public PipelineBuilder { + public: + explicit ComputePipelineBuilder(std::optional maxCache = std::nullopt) : PipelineBuilder(maxCache) {} + + ComputePipelineBuilder(const ComputePipelineBuilder&) = delete; + ComputePipelineBuilder& operator=(const ComputePipelineBuilder&) = delete; + + #define fluent ComputePipelineBuilder& + + fluent name(std::string&& name); + fluent layout(std::vector&& descLayouts, std::vector&& pushConstants); + fluent shader(std::string&& path); + + std::unique_ptr build() const override; + + private: + std::optional shaderPath; + }; + + /** + * Pipeline configures: + * - Shader Stages + * - Fixed Function stages + * - Vertex input bindings + * - Vertex attributes + * - Assembly + * - Tesselation + * - Viewport and Scissor + * - Rasterization + * - Multisampling + * - Depth testing + * - Stencil testing + * - Color blending + * - Dynamic states + * - Pipeline layout + * - Descriptor set layout + * - Push constant ranges + * + * Create a Pipeline with one of the builders above. + */ + class Pipeline { + public: + Pipeline(const Pipeline&) = delete; + Pipeline& operator=(const Pipeline&) = delete; + + ~Pipeline(); + + void bind(const VkCommandBuffer& buffer) const; + + const VkPipeline& operator*() const { return pipeline; } + const VkPipelineLayout& getLayout() const { return layout; } + VkPipelineBindPoint getBind() const { return bindPoint; } + + static VkPipelineColorBlendAttachmentState getAlphaBlendState(bool blending) { + return { + blending, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_OP_ADD, VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT + }; + } + + private: + friend std::unique_ptr GraphicsPipelineBuilder::build() const; + friend std::unique_ptr ComputePipelineBuilder::build() const; + + Pipeline(std::string name, const VkPipeline& line, const VkPipelineLayout& lay, VkPipelineBindPoint bPoint) + : name(std::move(name)), pipeline(line), layout(lay), bindPoint(bPoint) {} + + const std::string name; + // The active Pipeline layout. + const VkPipelineLayout layout; + // The active Pipeline instance. + const VkPipeline pipeline; + // Whether this is a graphics or compute pipeline + const VkPipelineBindPoint bindPoint; + }; +} diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/texture/RenderTexture.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/texture/RenderTexture.h deleted file mode 100644 index 1e76fb2..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/render/texture/RenderTexture.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#include - -class RenderTexture { -public: - // Create all image views and all framebuffers from a set of images, a format, a size, and the current rendering pass. - virtual void createViewsAndFramebuffer(std::vector images, VkFormat format, VkExtent2D extent, VkRenderPass pass) = 0; - // Create views for swapChainImages with the given format. - virtual void createViews(VkFormat format) = 0; - // Create a framebuffer for the swapChainImages, for the given pass. - virtual void createFramebuffer(VkExtent2D extent, VkRenderPass pass) = 0; - - virtual VkFramebuffer getFramebuffer(int ID) = 0; - - virtual void destroy() = 0; -}; - -class SingleRenderTexture : public RenderTexture { -public: - SingleRenderTexture(); - ~SingleRenderTexture(); - - // A list of all images involved with this texture (color, normals, etc) - std::vector swapChainImages; - // The sizes of all attached images. - VkExtent2D swapChainImageExtent; - - // Views - mipmaps, portions, crops, etc of the attached images. - std::vector swapChainImageViews; - // Framebuffers containing the images that can be bound and rendered from. - std::vector swapChainFramebuffers; - - VkFramebuffer getFramebuffer(int ID) override { return swapChainFramebuffers.at(ID); } - - // Create all image views and all framebuffers from a set of images, a format, a size, and the current rendering pass. - void createViewsAndFramebuffer(std::vector images, VkFormat format, VkExtent2D extent, VkRenderPass pass) override; - // Create views for swapChainImages with the given format. - void createViews(VkFormat format) override; - // Create a framebuffer for the swapChainImages, for the given pass. - void createFramebuffer(VkExtent2D extent, VkRenderPass pass) override; - - void destroy() override; -}; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/CommandBuffer.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/CommandBuffer.h deleted file mode 100644 index 1811ac6..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/CommandBuffer.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include - -class CommandBuffer { -public: - - CommandBuffer(); - ~CommandBuffer(); - - VkCommandPool commands; - std::vector buffers; - - void createCommandPoolAndBuffers(size_t images); - void beginCommandBuffer(VkCommandBuffer buffer); - void endCommandBuffer(VkCommandBuffer buffer); - - void createCommandPool(); - void allocateCommandBuffers(size_t size); - - void destroy(); -}; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/SwapChain.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/SwapChain.h index 7f715c1..b43cc3a 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/SwapChain.h +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/SwapChain.h @@ -4,6 +4,7 @@ #include #include #include +#include "vlkx/vulkan/abstraction/Image.h" class SwapChain { public: @@ -14,7 +15,8 @@ public: VkFormat format; VkExtent2D extent; - std::vector images; + std::vector> images; + std::unique_ptr multisampleImg; VkSurfaceFormatKHR chooseFormat(const std::vector& availableFormats); VkPresentModeKHR chooseMode(const std::vector& availableModes); diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/Tools.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/Tools.h index 4a1f3c6..3522e69 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/Tools.h +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/Tools.h @@ -4,19 +4,12 @@ #include #include -#include - #include +#include "VulkanDevice.h" +#include "exports.h" + namespace VkTools { - extern VmaAllocator g_allocator; - extern VkInstance g_Instance; - extern VkPhysicalDevice g_PhysicalDevice; - extern VkDevice g_Device; - extern uint32_t g_QueueFamily; - extern VkQueue g_Queue; - extern VkDebugReportCallbackEXT g_DebugReport; - struct ManagedImage { VkImage image; VmaAllocation allocation; @@ -27,194 +20,20 @@ namespace VkTools { VmaAllocation allocation; }; - ManagedImage createImage(VkFormat format, VkImageUsageFlags flags, VkExtent3D extent, VkDevice device); - VkSampler createSampler(VkFilter filters, VkSamplerAddressMode mode); - VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags, VkDevice device); - ManagedBuffer createGPUBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkDevice logicalDevice, VkPhysicalDevice physicalDevice, bool hostVisible = true); - uint32_t findMemoryIndex(uint32_t type, VkMemoryPropertyFlags properties, VkPhysicalDevice physicalDevice); - VkCommandBuffer createTempCommandBuffer(VkCommandPool pool, VkDevice logical); - void executeAndDeleteTempBuffer(VkCommandBuffer buffer, VkCommandPool pool, VkQueue queue, VkDevice logicalDevice); - void copyGPUBuffer(VkBuffer source, VkBuffer dest, VkDeviceSize length, VkDevice logical, VkQueue graphicsQueue, uint32_t queueIndex); + extern API VmaAllocator allocator; + ManagedImage createImage(VkFormat format, VkImageUsageFlags flags, VkExtent3D extent); - #ifdef VKTOOLS_IMPLEMENTATION - ManagedImage createImage(VkFormat format, VkImageUsageFlags flags, VkExtent3D extent, VkDevice device) { - // Set up image metadata - VkImageCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - info.pNext = nullptr; - info.format = format; - info.extent = extent; - info.mipLevels = 1; - info.arrayLayers = 1; - info.samples = VK_SAMPLE_COUNT_1_BIT; - info.tiling = VK_IMAGE_TILING_OPTIMAL; - info.usage = flags; + VkSampler createSampler(VkFilter filters, VkSamplerAddressMode mode, uint32_t mipping, VkDevice device); - // Prepare the managed image - ManagedImage image {}; + VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags, uint32_t mipping, uint32_t layers, + VkDevice device); - // Set up image allocation - VmaAllocationCreateInfo allocateInfo = {}; - allocateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + ManagedBuffer createGPUBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, + VkDevice logicalDevice, VkPhysicalDevice physicalDevice, bool hostVisible = true); - // Allocate + create the image - vmaCreateImage(g_allocator, &info, &allocateInfo, &image.image, &image.allocation, nullptr); + void immediateExecute(const std::function &execute, VulkanDevice *dev); - return image; + void copyGPUBuffer(VkBuffer source, VkBuffer dest, VkDeviceSize length, VulkanDevice *dev); - } - - VkSampler createSampler(VkFilter filters, VkSamplerAddressMode mode) { - VkSamplerCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - info.pNext = nullptr; - info.magFilter = filters; - info.minFilter = filters; - info.addressModeU = mode; - info.addressModeV = mode; - info.addressModeW = mode; - - VkSampler sampler; - vkCreateSampler(g_Device, &info, nullptr, &sampler); - - return sampler; - } - - VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags, VkDevice device) { - // Raw information about the image - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = format; - - // Information about the things we want to create - size, mip levels. - viewInfo.subresourceRange.aspectMask = flags; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - - VkImageView imageView; - if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) - throw std::runtime_error("Failed to create texture image view."); - - return imageView; - } - - ManagedBuffer createGPUBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkDevice logicalDevice, VkPhysicalDevice physicalDevice, bool hostVisible) { - // Prepare for creation of a buffer - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = usage; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - ManagedBuffer buffer; - - VmaAllocationCreateInfo vmaInfo = {}; - vmaInfo.usage = hostVisible ? VMA_MEMORY_USAGE_CPU_ONLY : VMA_MEMORY_USAGE_GPU_ONLY; - vmaInfo.requiredFlags = properties; - - // Create the buffer. - if (vmaCreateBuffer(g_allocator, &bufferInfo, &vmaInfo, &buffer.buffer, &buffer.allocation, nullptr) != VK_SUCCESS) - throw std::runtime_error("Unable to create GPU buffer"); - - return buffer; - } - - uint32_t findMemoryIndex(uint32_t type, VkMemoryPropertyFlags properties, VkPhysicalDevice physicalDevice) { - // Get the physical properties of the device. - VkPhysicalDeviceMemoryProperties physProperties; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &physProperties); - - // Iterate the device and search for a suitable index - for (uint32_t i = 0; i < physProperties.memoryTypeCount; i++) - // If the type matches, and the properties are what we desire, then ship it. - if ((type & (1 << i)) && ((physProperties.memoryTypes[i].propertyFlags & properties) == properties)) - return i; - - throw std::runtime_error("Unable to find a suitable memory type on the physical device."); - } - - VkCommandBuffer createTempCommandBuffer(VkCommandPool pool, VkDevice logical) { - // Prepare to allocate a command buffer - VkCommandBufferAllocateInfo allocateInfo = {}; - allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocateInfo.commandPool = pool; - allocateInfo.commandBufferCount = 1; - - // Allocate the buffer - VkCommandBuffer buffer; - vkAllocateCommandBuffers(logical, &allocateInfo, &buffer); - - // Prepare to begin the new buffer. - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - // Begin listening on the new buffer. - vkBeginCommandBuffer(buffer, &beginInfo); - - return buffer; - } - - void executeAndDeleteTempBuffer(VkCommandBuffer buffer, VkCommandPool pool, VkQueue queue, VkDevice logicalDevice) { - // Stop listening on the buffer - vkEndCommandBuffer(buffer); - - // Prepare to execute the commands in the buffer - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &buffer; - - // Submit the commands to be executed - vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); - - // Wait for the GPU to finish executing - vkQueueWaitIdle(queue); - - // Delete the now unusable buffers - vkFreeCommandBuffers(logicalDevice, pool, 1, &buffer); - } - - void copyGPUBuffer(VkBuffer source, VkBuffer dest, VkDeviceSize length, VkDevice logical, VkQueue graphicsQueue, uint32_t queueIndex) { - - // Prepare to create a temporary command pool. - VkCommandPool pool; - VkCommandPoolCreateInfo poolCreateInfo = {}; - poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolCreateInfo.queueFamilyIndex = queueIndex; - poolCreateInfo.flags = 0; - - // Create the pool - if (vkCreateCommandPool(logical, &poolCreateInfo, nullptr, &pool) != VK_SUCCESS) - throw std::runtime_error("Unable to allocate a temporary command pool"); - - // Allocate a buffer - VkCommandBuffer commands = createTempCommandBuffer(pool, logical); - - // ------ Commands are saved into the commands field ------ // - - // Prepare to copy the data between buffers - VkBufferCopy copyInfo = {}; - copyInfo.srcOffset = 0; - copyInfo.dstOffset = 0; - copyInfo.size = length; - - // Copy the data. - vkCmdCopyBuffer(commands, source, dest, 1, ©Info); - - // ------ Commands are no longer saved into the commands field ------ // - - executeAndDeleteTempBuffer(commands, pool, graphicsQueue, logical); - - // Cleanup the temporary buffer and pool we created - vkDestroyCommandPool(logical, pool, nullptr); - } - - #endif } \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/ValidationAndExtension.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/ValidationAndExtension.h index 035280a..0407373 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/ValidationAndExtension.h +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/ValidationAndExtension.h @@ -11,7 +11,8 @@ public: ~ValidationAndExtension(); const std::vector requiredValidations = { - "VK_LAYER_KHRONOS_validation" + "VK_LAYER_KHRONOS_validation", + //"VK_LAYER_LUNARG_api_dump" }; VkDebugReportCallbackEXT callback; diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanDevice.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanDevice.h index 04e7a02..b4a409b 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanDevice.h +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanDevice.h @@ -30,6 +30,7 @@ public: /** Physical Devices **/ VkPhysicalDevice physical; + VkPhysicalDeviceLimits limits; SwapChainMeta swapChain; QueueFamilies queueData; diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanManager.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanManager.h deleted file mode 100644 index 1915521..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanManager.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -class VulkanManager { -public: - VulkanManager(); - ~VulkanManager(); - -#ifdef _DEBUG - static const bool validationRequired = true; -#else - static const bool validationRequired = false; -#endif - - // VulkanManager is a singleton class. - static VulkanManager* instance; - static VulkanManager* getInstance(); - - // Initialize all Vulkan context and prepare validations in debug mode. - void initVulkan(SDL_Window* window); - void createAppAndVulkanInstance(bool enableValidation, ValidationAndExtension* validations); - - // Start and end a frame render. - void startDraw(); - void endDraw(); - - // Cleanup after the application has closed. - void cleanup(); - - void useRayTrace() { rayTraceMode = true; } - - VkInstance getVulkan() { return vulkan; } - VulkanDevice* getDevice() { return device; } - SwapChain* getSwapchain() { return swapchain; } - RenderPass* getRenderPass() { return renderPass; } - VkCommandBuffer getCurrentCommandBuffer() { return currentCommandBuffer; } - VmaAllocator getAllocator() { return allocator; } - RenderTexture* getRenderTarget() { return renderTexture; } - -private: - // To keep track of the window during... stuff - SDL_Window* wnd; - - // To handle the validation of Vulkan API usage (because fuck you, it's your problem now) - ValidationAndExtension* validators{}; - // To manage interaction with the hardware - VulkanDevice* device{}; - // To handle the framebuffers - SwapChain* swapchain{}; - // To handle the timing of rendering - RenderPass* renderPass{}; - - // To handle automatic management of memory. - VmaAllocator allocator{}; - - // The default RenderTexture, mirroring the SwapChain to the viewport. - RenderTexture* renderTexture; - // The command buffers used when telling the firmware to do things for us. - CommandBuffer* buffers{}; - - // To manage the Vulkan context that was passed to us by the API - VkInstance vulkan{}; - // To manage the canvas that was given to us by GLFW - VkSurfaceKHR surface{}; - - // The index of the texture that is currently being used by the GPU. - uint32_t imageIndex = 0; - // The command buffer currently being used by the GPU. - VkCommandBuffer currentCommandBuffer{}; - - // The maximum number of frames that can be dealt with at a time. - const int MAX_FRAMES = 2; // Double-buffering requires two frames in memory - // Raised when a new image is available - VkSemaphore newImageSem{}; - // Raised when a render is finished - VkSemaphore renderDoneSem{}; - // Stores fences for frames that are currently "in flight". - std::vector inFlight; - - bool rayTraceMode; - -}; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanModule.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanModule.h new file mode 100644 index 0000000..6bf87d7 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/VulkanModule.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include + +#include +#include + +#include +#include +#include "SwapChain.h" + +namespace vlkx { class ScreenRenderPassManager; } + +class VulkanModule : public ShadowEngine::RendererModule { + SHObject_Base(VulkanModule); +public: + + VulkanModule(); + ~VulkanModule() override; + +#ifdef _DEBUG + static const bool validationRequired = true; +#else + static const bool validationRequired = false; +#endif + + void PreInit() override; + + void Init() override; + + void Recreate() override; + + void Update(int frame) override; + + void PreRender() override; + + void Render(VkCommandBuffer& commands, int frame) override; + + void OverlayRender() override; + + void LateRender(VkCommandBuffer& commands, int frame) override; + + void AfterFrameEnd() override; + + void Destroy() override; + + void Event(SDL_Event* e) override; + + void BeginRenderPass(const std::unique_ptr& commands) override; + + void EnableEditor() override; + + VkExtent2D GetRenderExtent() override; + + // VulkanModule is a singleton class. + static VulkanModule* instance; + static VulkanModule* getInstance(); + + // Initialize all Vulkan context and prepare validations in debug mode. + void initVulkan(SDL_Window* window); + void createAppAndVulkanInstance(bool enableValidation, ValidationAndExtension* validations); + + // Start and end a frame render. + void startDraw(); + void endDraw(); + + // Cleanup after the application has closed. + void cleanup(); + + VkInstance getVulkan() { return vulkan; } + VulkanDevice* getDevice() { return device; } + SwapChain* getSwapchain() { return swapchain; } + VmaAllocator getAllocator() { return allocator; } + SDL_Window* getWind() { return wnd; } + const std::unique_ptr& getRenderPass(); + + +private: + bool editorEnabled = false; + std::vector editorRenderPlanes; + std::vector> editorContentFrames; + + // The SDL Window contains the size of the drawable area. + SDL_Window* wnd; + // To handle the validation of Vulkan API usage + ValidationAndExtension* validators{}; + // To manage interaction with the hardware + VulkanDevice* device{}; + // To handle the framebuffers + SwapChain* swapchain{}; + // To handle automatic management of memory. + VmaAllocator allocator{}; + // To manage the Vulkan context that was passed to us by the API + VkInstance vulkan{}; + // To manage the canvas that was given to us by GLFW + VkSurfaceKHR surface{}; + +}; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Buffer.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Buffer.h new file mode 100644 index 0000000..ecd3d36 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Buffer.h @@ -0,0 +1,412 @@ +#pragma once + +#include +#include +#include +#include +#include "vlkx/vulkan/Tools.h" + +namespace vlkx { + // Root buffer class. + // Used to store & move data between the CPU and GPU. + // Basically; hotspot! + // Utilities and subclasses exist to optimise and speed up transfer and management of data in bulk. + class Buffer { + public: + // Metadata of CPU->GPU data copying. + struct CopyMeta { + const void* data; // The start of data in RAM + VkDeviceSize length; // The amount of data to move + VkDeviceSize start; // The start (destination) in GPU memory + }; + + // Metadata of bulk CPU->GPU data copying. + struct BulkCopyMeta { + VkDeviceSize length; // The total data size of all transfers. + std::vector metas; + }; + + Buffer(const Buffer&) = delete; + Buffer& operator=(const Buffer&) = delete; + + Buffer(); + + virtual ~Buffer() { + } + + protected: + }; + + /*******************************************/ + /** */ + /** START OF DATA BUFFERS */ + /** */ + /*******************************************/ + + // A buffer that stores data on GPU. + // Usage of the data is determined by child classes. + class DataBuffer : public Buffer { + public: + DataBuffer(const DataBuffer&) = delete; + DataBuffer& operator=(const DataBuffer&) = delete; + + DataBuffer() = default; + + ~DataBuffer() override { + vmaDestroyBuffer(VkTools::allocator, managed.buffer, managed.allocation); + } + + protected: + using Buffer::Buffer; + + void setBuffer(const VkTools::ManagedBuffer& buffer) { managed = buffer; } + VkTools::ManagedBuffer get() const { return managed; } + const VkBuffer& getBuffer() const { return managed.buffer; } + + private: + VkTools::ManagedBuffer managed; + }; + + // A buffer visible to both GPU and CPU. + // Useful for uploading data to GPU for format conversions. + class StagingBuffer : public DataBuffer { + public: + StagingBuffer(const BulkCopyMeta& copyMeta); + + StagingBuffer(const StagingBuffer&) = delete; + StagingBuffer& operator=(const StagingBuffer&) = delete; + + void copy(const VkBuffer& target) const; + + private: + const VkDeviceSize dataSize; + }; + + // Root class of vertex buffers. + // Provides utilities for subclasses. + class VertexBuffer : public DataBuffer { + public: + VertexBuffer(const VertexBuffer&) = delete; + VertexBuffer& operator=(const VertexBuffer&) = delete; + + // Get attributes of vertexes in the buffer + // Location will start from "start" + // Binding will not be set + std::vector getAttrs(uint32_t start) const; + + // Draw these vertexes without a buffer per vertex. + static void draw(const VkCommandBuffer& buffer, uint32_t verts, uint32_t instances); + + protected: + friend class DynamicBuffer; + + explicit VertexBuffer(std::vector&& attrs) : DataBuffer(), attributes(attrs) {} + + // Initialize device memory and the managed buffer. + // indices and vertexes are put in the same buffer. + // if dynamic, the buffer will be host visible, this allows dynamic text. + // otherwise, the buffer is device local. + void create(VkDeviceSize totalSize, bool dynamic, bool indexes); + + const std::vector attributes; + }; + + /*******************************************/ + /** */ + /** END OF DATA BUFFERS */ + /** */ + /*******************************************/ + + // A simple plugin to allow the vertex buffer to be widened when reserved with a larger size. + class DynamicBuffer { + public: + DynamicBuffer(const DynamicBuffer&) = delete; + DynamicBuffer& operator=(const DynamicBuffer&) = delete; + + ~DynamicBuffer() = default; + + protected: + + DynamicBuffer(size_t size, bool hasIndices, VertexBuffer* buffer); + + // Reallocate the vertex buffer if the given pSize is larger than the available space + void resize(size_t pSize); + + VkDeviceSize bufferSize() const { return size; } + + private: + + const bool hasIndices; + VertexBuffer* vertexBuffer; + VkDeviceSize size = 0; + }; + + /*******************************************/ + /** */ + /** START OF PER-VERTEX BUFFERS */ + /** */ + /*******************************************/ + + // Root class of buffers that store per-vertex data. + // eg. shader data + class PerVertexBuffer : public VertexBuffer { + public: + // Interprets the layout of data in containers (vector, etc) + struct VertexDataMeta { + template + VertexDataMeta(const C& cont, int unitsPerMesh) : data(cont.data()), unitsPerMesh(unitsPerMesh), sizePerMesh(sizeof(cont[0]) * unitsPerMesh) {} + + template + VertexDataMeta(const C& cont) : VertexDataMeta(cont, static_cast(cont.size())) {} + + const void* data; + int unitsPerMesh; + size_t sizePerMesh; + }; + + // Interface for buffer data. + class BufferDataMeta { + public: + virtual ~BufferDataMeta() = default; + // Populate info and return a bulk copy meta for copying the data to device + virtual BulkCopyMeta prepareCopy(PerVertexBuffer* buffer) const = 0; + // Indicate whether the buffer contains index data too + virtual bool hasIndices() const = 0; + }; + + // Meshes do not share indices, with variable vertices. + class NoIndexBufferMeta : public BufferDataMeta { + public: + explicit NoIndexBufferMeta(std::vector&& perVertex) : perMeshVertices(perVertex) {} + + BulkCopyMeta prepareCopy(PerVertexBuffer* buffer) const override; + bool hasIndices() const override { return false; }; + private: + const std::vector perMeshVertices; + }; + + // Meshes share indices, with static vertices. + class SharedIndexMeta : public BufferDataMeta { + public: + SharedIndexMeta(int meshes, const VertexDataMeta& perVertex, const VertexDataMeta& sharedIndices) : meshes(meshes), + perMeshVertex(perVertex), + sharedIndices(sharedIndices) {} + BulkCopyMeta prepareCopy(PerVertexBuffer* buffer) const override; + bool hasIndices() const override { return true; }; + private: + const int meshes; + const VertexDataMeta perMeshVertex; + const VertexDataMeta sharedIndices; + }; + + // Meshes do not share indexes, with variable indices and vertices. + class NoShareMeta : public BufferDataMeta { + public: + struct PerMesh { + VertexDataMeta indices; + VertexDataMeta vertices; + }; + + explicit NoShareMeta(std::vector&& perMesh) : perMeshMeta(std::move(perMesh)) {} + + BulkCopyMeta prepareCopy(PerVertexBuffer* buffer) const override; + bool hasIndices() const override { return true; }; + private: + const std::vector perMeshMeta; + }; + + PerVertexBuffer(const PerVertexBuffer&) = delete; + PerVertexBuffer& operator=(const PerVertexBuffer&) = delete; + + // Render mesh a given number of times, into a recording buffer. + void draw(const VkCommandBuffer& buffer, uint32_t bind, int index, uint32_t instances) const; + + protected: + using VertexBuffer::VertexBuffer; + + // Stores vertex data for buffers without indices + struct MeshDataNoIndex { + struct Info { + uint32_t vertexCount; + VkDeviceSize vertexStart; + }; + + std::vector info; + }; + + // Stores vertex and index data for buffers with both + struct MeshDataIndex { + struct Info { + uint32_t indexCount; + VkDeviceSize indexStart; + VkDeviceSize vertexStart; + }; + + std::vector info; + }; + + std::variant* getInfo() { return &meshDataInfo; } + + private: + + std::variant meshDataInfo; + }; + + // Stores static data for one-time upload. + class StaticPerVertexBuffer : public PerVertexBuffer { + public: + StaticPerVertexBuffer(const BufferDataMeta& info, std::vector&& attrs); + + StaticPerVertexBuffer(const StaticPerVertexBuffer&) = delete; + StaticPerVertexBuffer& operator=(const StaticPerVertexBuffer&) = delete; + }; + + // Stores host-visible data that can be reallocated. + class DynamicPerVertexBuffer : public PerVertexBuffer, public DynamicBuffer { + public: + DynamicPerVertexBuffer(size_t size, std::vector&& attrs) : PerVertexBuffer(std::move(attrs)), DynamicBuffer(size, true, this) {} + + DynamicPerVertexBuffer(const DynamicPerVertexBuffer&) = delete; + DynamicPerVertexBuffer& operator=(const DynamicPerVertexBuffer&) = delete; + + void copyToDevice(const BufferDataMeta& meta); + }; + + /*******************************************/ + /** */ + /** END OF PER-VERTEX BUFFERS */ + /** */ + /*******************************************/ + + // Root class of buffers that store vertex data per instance of a mesh. + class PerInstanceVertexBuffer : public VertexBuffer { + public: + PerInstanceVertexBuffer(const PerInstanceVertexBuffer&) = delete; + PerInstanceVertexBuffer& operator=(const PerInstanceVertexBuffer&) = delete; + + void bind(const VkCommandBuffer& commands, uint32_t bindPoint, int offset) const; + + uint32_t getSize() const { return sizePerInstance; } + + protected: + PerInstanceVertexBuffer(uint32_t size, std::vector&& attrs) : VertexBuffer(std::move(attrs)), sizePerInstance(size) {} + private: + const uint32_t sizePerInstance; + }; + + // Stores vertices that are static per instance of the mesh. + class StaticPerInstanceBuffer : public PerInstanceVertexBuffer { + public: + StaticPerInstanceBuffer(uint32_t size, const void* data, uint32_t instances, std::vector&& attrs); + + template + StaticPerInstanceBuffer(const C& cont, std::vector&& attrs) : StaticPerInstanceBuffer(sizeof(cont[0]), cont.data(), CONTAINER_SIZE(cont), std::move(attrs)) {} + + StaticPerInstanceBuffer(const StaticPerInstanceBuffer&) = delete; + StaticPerInstanceBuffer& operator=(const StaticPerInstanceBuffer&) = delete; + }; + + // Stores vertices of meshes that are dynamic (ie. text, shifting meshes + class DynamicPerInstanceBuffer : public PerInstanceVertexBuffer, public DynamicBuffer { + public: + DynamicPerInstanceBuffer(uint32_t size, size_t maxInstances, std::vector&& attrs) : PerInstanceVertexBuffer(size, std::move(attrs)), DynamicBuffer(size * maxInstances, false, this) {} + + DynamicPerInstanceBuffer(const DynamicPerInstanceBuffer&) = delete; + DynamicPerInstanceBuffer& operator=(const DynamicPerInstanceBuffer*) = delete; + + void copyToDevice(const void* data, uint32_t instances); + + template + void copyToDevice(const C& cont) { + copyToDevice(cont.data(), CONTAINER_SIZE(cont)); + } + }; + + /*******************************************/ + /** */ + /** END OF PER-INSTANCE BUFFERS */ + /** */ + /*******************************************/ + + // Holds uniform data on host and device. + // Supports superallocating (allocating more than one "set" of uniforms at once) + // Data is stored on host and device simultaneously, so set the host data and flush it to the device. + class UniformBuffer : public DataBuffer { + public: + UniformBuffer(size_t chunkSize, int chunks); + + UniformBuffer(const UniformBuffer&) = delete; + UniformBuffer& operator=(const UniformBuffer&) = delete; + + ~UniformBuffer() override { delete data; } + + // Whether this buffer holds a single chunk (is not superallocated). + // Simplifies certain algorithms significantly if you know this beforehand + bool isSingle() const { return numChunks == 1; } + + // Get the data in the buffer, casted to the given type + template + DataType* getData(int index) const { + checkIndex(index); + return reinterpret_cast(data + chunkSize * index); + } + + // Upload (flush) the uniform to the GPU + void upload(int index) const; + void upload(int index, VkDeviceSize dataSize, VkDeviceSize start) const; + + static VkDescriptorType getDescriptorType() { return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; } + + VkDescriptorBufferInfo getDescriptorInfo(int index) const; + + private: + void checkIndex(int index) const; + + char* data; + const size_t chunkSize; + const int numChunks; + + size_t chunkLength; + }; + + // A small, highly efficient buffer much like the Uniform Buffer. + class PushConstant { + public: + // Size must be < 128. + PushConstant(size_t size, int numFrames); + + PushConstant(const PushConstant&) = delete; + PushConstant& operator=(const PushConstant&) = delete; + + ~PushConstant() { delete[] data; } + + // Whether this buffer holds a single chunk (is not superallocated). + // Simplifies certain algorithms significantly if you know this beforehand + bool isSingle() const { return numFrames == 1; } + + uint32_t getSize() const { return sizePerFrame; } + + // Get the data in the buffer, casted to the given type + template + DataType* getData(int frame) const { + checkIndex(frame); + return reinterpret_cast(data + (sizePerFrame * frame)); + } + + VkPushConstantRange makeRange(VkShaderStageFlags stage) { + return VkPushConstantRange { stage, 0, sizePerFrame }; + } + + // Upload (flush) the uniform to the GPU + void upload(const VkCommandBuffer& commands, const VkPipelineLayout& pipelineLayout, int frame, uint32_t offset, VkShaderStageFlags stage) const; + + + private: + void checkIndex(int index) const; + + char* data; + const uint32_t sizePerFrame; + const int numFrames; + }; + +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Commands.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Commands.h new file mode 100644 index 0000000..c426c09 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Commands.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include "Queue.h" +#include "vlkx/vulkan/VulkanDevice.h" +#include +#include + +namespace vlkx { + + // Root class of VkCommandBuffer wrappers. + class CommandBuffer { + public: + using Command = std::function; + + CommandBuffer(const CommandBuffer&) = delete; + CommandBuffer& operator=(const CommandBuffer&) = delete; + + virtual ~CommandBuffer() { + vkDestroyCommandPool(dev->logical, pool, nullptr); + } + protected: + CommandBuffer(); + + void setPool(const VkCommandPool& newPool) { pool = newPool; } + VulkanDevice* dev; + private: + VkCommandPool pool; + }; + + // A command buffer that will be immediately executed. + class ImmediateCommand : public CommandBuffer { + public: + ImmediateCommand(Queue queue); + + ImmediateCommand(const ImmediateCommand&) = delete; + ImmediateCommand& operator=(const ImmediateCommand&) = delete; + + void run(const Command& cmd); + + private: + const Queue queue; + VkCommandBuffer commands; + }; + + // A command buffer that will be reused every frame. + class RenderCommand : public CommandBuffer { + public: + using Command = std::function; + using Update = std::function; + + ~RenderCommand() override { + // Destroy our own data + vkDestroySemaphore(dev->logical, renderDoneSem, nullptr); + vkDestroySemaphore(dev->logical, newImageSem, nullptr); + + for (size_t i = 0; i < 2; i++) { + vkDestroyFence(dev->logical, inFlight[i], nullptr); + } + } + + RenderCommand(int frames); + + RenderCommand(const RenderCommand&) = delete; + RenderCommand& operator=(const RenderCommand&) = delete; + + uint32_t getFrame() { return imageIndex; } + + void nextFrame() { imageIndex = (imageIndex + 1) % 2; } + + std::optional execute(int frame, const VkSwapchainKHR& swapchain, const Update& update, const Command& cmd); + // Renders a single frame out, no semaphores or fences. + std::optional executeSimple(int frame, const Update& update, const Command& cmd); + + private: + std::vector commands; + // Raised when a new image is available + VkSemaphore newImageSem; + // Raised when a render is finished + VkSemaphore renderDoneSem; + // Stores fences for frames that are currently "in flight". + std::vector inFlight; + + // The index of the texture that is currently being used by the GPU. + uint32_t imageIndex = 0; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Descriptor.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Descriptor.h new file mode 100644 index 0000000..336f9c6 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Descriptor.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace vlkx { + + class Descriptor { + public: + using TextureType = vlkxtemp::ModelLoader::TextureType; + using BufferInfos = std::map>; + using ImageInfos = std::map>; + + struct Meta { + struct Binding { + uint32_t bindPoint; + uint32_t length; + }; + + VkDescriptorType type; + VkShaderStageFlags stage; + std::vector bindings; + }; + + Descriptor(const Descriptor&) = delete; + Descriptor& operator=(const Descriptor&) = delete; + + virtual ~Descriptor() { + vkDestroyDescriptorSetLayout(VulkanModule::getInstance()->getDevice()->logical, layout, nullptr); + } + + const VkDescriptorSetLayout& getLayout() const { return layout; } + + protected: + explicit Descriptor() = default; + + void setLayout(const VkDescriptorSetLayout& newLayout) { layout = newLayout; } + + private: + VkDescriptorSetLayout layout; + }; + + class StaticDescriptor : public Descriptor { + public: + + StaticDescriptor(std::vector metas); + StaticDescriptor(const StaticDescriptor&) = delete; + StaticDescriptor& operator=(const StaticDescriptor&) = delete; + + ~StaticDescriptor() override { + vkDestroyDescriptorPool(VulkanModule::getInstance()->getDevice()->logical, pool, nullptr); + } + + const StaticDescriptor& buffers(VkDescriptorType type, const BufferInfos& infos) const; + const StaticDescriptor& images(VkDescriptorType type, const ImageInfos& infos) const; + + void bind(const VkCommandBuffer& commands, const VkPipelineLayout& layout, VkPipelineBindPoint bindPoint) const; + + private: + + const StaticDescriptor& updateSet(const std::vector& write) const; + + VkDescriptorPool pool; + VkDescriptorSet set; + }; + + // TODO: dynamic sets +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Image.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Image.h new file mode 100644 index 0000000..b78700b --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Image.h @@ -0,0 +1,331 @@ +#pragma once + +#include "vlkx/vulkan/Tools.h" +#include "ImageUsage.h" +#include +#include "Buffer.h" +#include + +#include + +namespace vlkx { + + // Describes an image without initializing or storing any heavy data. + class ImageDescriptor { + public: + enum class Type { Single, Cubemap }; + struct Dimension { + uint32_t width; + uint32_t height; + uint32_t channels; + + VkExtent2D getExtent() const { return { width, height }; } + size_t getSize() const { return width * height * channels; } + }; + + Type getType() const { return type; } + VkExtent2D getExtent() const { return dimensions.getExtent(); } + uint32_t getWidth() const { return dimensions.width; } + uint32_t getHeight() const { return dimensions.height; } + uint32_t getChannels() const { return dimensions.channels; } + + std::vector getData() const { + if (type == Type::Single) return { (void*) data }; + std::vector dataPtrs; + dataPtrs.reserve(6); + + size_t offset = 0; + for (size_t i = 0; i < 6; i++) { + dataPtrs.emplace_back((char*) data + offset); + offset += dimensions.getSize(); + } + + return dataPtrs; + } + + int getLayers() const { return type == Type::Single ? 1 : 6; } + + ImageDescriptor(Type t, const Dimension& d, const void* ptr) : type(t), dimensions(d), data(ptr) {} + + private: + Type type; + Dimension dimensions; + const void* data; + + }; + + // A staging buffer specialized for uploading images. + class ImageStagingBuffer : public StagingBuffer { + public: + using StagingBuffer::StagingBuffer; + + ImageStagingBuffer(const ImageStagingBuffer&) = delete; + ImageStagingBuffer& operator=(const ImageStagingBuffer&) = delete; + + void copy(const VkImage& target, const VkExtent3D& extent, uint32_t layers) const; + }; + + // Root class that stores image data on GPU buffers + class ImageBuffer : public Buffer { + public: + ImageBuffer(const ImageBuffer&) = delete; + ImageBuffer& operator=(const ImageBuffer&) = delete; + + ~ImageBuffer() override { + vmaDestroyImage(VkTools::allocator, image.image, image.allocation); + } + + const VkTools::ManagedImage& get() const { return image; } + const VkImage& getImage() const { return image.image; } + + protected: + using Buffer::Buffer; + + void setImage(const VkTools::ManagedImage newImg) { image = newImg; } + + private: + VkTools::ManagedImage image; + + }; + + // Base class of all images; stores the common data. + class Image { + public: + Image(const Image&) = delete; + Image& operator=(const Image&) = delete; + + virtual ~Image() { + vkDestroyImageView(dev->logical, view, nullptr); + } + + static VkDescriptorType getSampleType() { return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; } + static VkDescriptorType getLinearType() { return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; } + + static ImageDescriptor loadSingleFromDisk(std::string path, bool flipY); + // The following are left unimplemented intentionally. + //static ImageDescriptor loadSingleFromVFS(std::string path, bool flipY); + static ImageDescriptor loadCubeFromDisk(const std::string& directory, const std::array& files, bool flipY); + //static ImageDescriptor loadCubeFromVFS(std::string directory, const std::array& files, bool flipY); + + virtual ImageUsage getUsage() const { return ImageUsage {}; } + + const VkTools::ManagedImage& operator*() const { return get(); } + + virtual const VkTools::ManagedImage& get() const = 0; + virtual const VkImage& getImage() const = 0; + + const VkImageView& getView() const { return view; } + const VkExtent2D& getExtent() const { return extent; } + VkFormat getFormat() const { return format; } + virtual VkSampleCountFlagBits getSamples() const { return VK_SAMPLE_COUNT_1_BIT; } + + + protected: + Image(const VkExtent2D& ext, VkFormat form); + + void setView(const VkImageView& imgView) { view = imgView; } + + VulkanDevice* dev; + VkImageView view; + VkExtent2D extent; + VkFormat format; + VkSampleCountFlagBits sampleCount; + }; + + // Configures image sampling in a sensible and extensible way + class ImageSampler { + public: + struct Config { + explicit Config(VkFilter filter = VK_FILTER_LINEAR, VkSamplerAddressMode mode = VK_SAMPLER_ADDRESS_MODE_REPEAT) : filter(filter), mode(mode) {} + + VkFilter filter; + VkSamplerAddressMode mode; + }; + + ImageSampler(int mipLevels, const Config& config); + + ImageSampler(const ImageSampler&) = delete; + ImageSampler& operator=(const ImageSampler&) = delete; + + ~ImageSampler() { + vkDestroySampler(dev->logical, sampler, nullptr); + } + + const VkSampler& operator*() const { return sampler; } + + private: + VkSampler sampler; + VulkanDevice* dev; + }; + + // Root of images which can be sampled. + class SamplableImage { + public: + virtual ~SamplableImage() = default; + + // Return a VkDescriptorImageInfo we can use to update sets. + virtual VkDescriptorImageInfo getInfo(VkImageLayout layout) const = 0; + VkDescriptorImageInfo getInfoForSampling() const { return getInfo(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } + VkDescriptorImageInfo getInfoForLinear() const { return getInfo(VK_IMAGE_LAYOUT_GENERAL); } + }; + + // A samplable image that lives on the GPU, with optional mipmapping. + // Use a RefCountedTexture when loading from files. + class TextureImage : public Image, public SamplableImage { + public: + // Image metadata + struct Meta { + VkExtent2D getExtent() const { return { width, height }; } + VkExtent3D get3DExtent() const { return { width, height, channels }; } + + Buffer::BulkCopyMeta getCopyMeta() const; + + std::vector data; + std::vector usages; + VkFormat format; + uint32_t width; + uint32_t height; + uint32_t channels; + }; + + TextureImage(bool mipmapping, const ImageSampler::Config& samplerConfig, const Meta& meta); + TextureImage(bool mipmapping, const ImageDescriptor& image, const std::vector& usages, const ImageSampler::Config& config); + + TextureImage(const TextureImage&) = delete; + TextureImage& operator=(const TextureImage&) = delete; + + const VkTools::ManagedImage& get() const override { return buffer.get(); } + const VkImage& getImage() const override { return buffer.getImage(); } + + VkDescriptorImageInfo getInfo(VkImageLayout layout) const override { + return { *sampler, getView(), layout }; + } + // Textures are sampled in fragment shaders. + ImageUsage getUsage() const override { + return ImageUsage::sampledFragment(); + } + private: + class TextureBuffer : public ImageBuffer { + public: + TextureBuffer(bool mipmaps, const Meta& meta); + + TextureBuffer(const TextureBuffer&) = delete; + TextureBuffer& operator=(const TextureBuffer&) = delete; + + int getMipping() const { return mipLevels; } + private: + int mipLevels = 1; + }; + + const TextureBuffer buffer; + const ImageSampler sampler; + }; + + // A texture image that lives on GPU that is reference counted. + // This allows it to be reused multiple times without reading the file in more than once. + // It also allows the texture to be destructed automatically once nothing in the scene uses it, for eg. level changes. + class RefCountedTexture : public SamplableImage { + public: + // Cubemaps are simply 6 textures, so we include them here for easy instantiation. + struct CubemapLocation { + std::string directory; + std::array files; + }; + + // Reference Counting works on both individual files and cubemaps, so we put them together. + using ImageLocation = std::variant; + + RefCountedTexture(const ImageLocation& location, std::vector usages, const ImageSampler::Config& config) + : texture(get(location, std::move(usages), config)) {} + + RefCountedTexture(RefCountedTexture&&) noexcept = default; + RefCountedTexture& operator=(RefCountedTexture&&) noexcept = default; + + VkDescriptorImageInfo getInfo(VkImageLayout layout) const override { + return texture->getInfo(layout); + } + + const Image* operator->() const { return texture.operator->(); } + + private: + using ReferenceCounter = shadowutil::RefCounter; + // Get or load the specified image. + static ReferenceCounter get(const ImageLocation& location, const std::vector& usages, const ImageSampler::Config& config); + + ReferenceCounter texture; + }; + + // TODO: unowned, offscreen images. + + // Image that can be used as a depth / stencil buffer attachment. + class DepthStencilImage : public Image { + public: + DepthStencilImage(const DepthStencilImage&) = delete; + DepthStencilImage& operator=(const DepthStencilImage&) = delete; + + DepthStencilImage(const VkExtent2D& extent); + + const VkTools::ManagedImage& get() const override { return buffer.get(); } + const VkImage& getImage() const override { return buffer.getImage(); } + + private: + class DepthStencilBuffer : public ImageBuffer { + public: + DepthStencilBuffer(const VkExtent2D& extent, VkFormat format); + DepthStencilBuffer(const DepthStencilBuffer&) = delete; + DepthStencilBuffer& operator=(const DepthStencilBuffer&) = delete; + }; + + const DepthStencilBuffer buffer; + }; + + // Image that references an existing image on the swapchain + class SwapchainImage : public Image { + public: + SwapchainImage(const SwapchainImage&) = delete; + SwapchainImage& operator=(const SwapchainImage&) = delete; + + SwapchainImage(const VkImage& image, const VkExtent2D& extent, VkFormat format); + + const VkTools::ManagedImage& get() const override { return managed; } + const VkImage& getImage() const override { return image; } + + private: + VkImage image; + VkTools::ManagedImage managed; + }; + + class MultisampleImage : public Image { + public: + enum class Mode { + MostEfficient, + Highest + }; + + static std::unique_ptr createColor(const Image& targetImage, Mode mode); + static std::unique_ptr createDepthStencilMS(const VkExtent2D& extent, Mode mode); + static std::unique_ptr createDepthStencil(VkExtent2D& extent, std::optional mode); + + const VkTools::ManagedImage& get() const override { return buffer.get(); } + const VkImage& getImage() const override { return buffer.getImage(); } + + VkSampleCountFlagBits getSamples() const override { return samples; } + private: + class MultisampleBuffer : public ImageBuffer { + public: + enum class Type { Color, DepthStencil }; + + MultisampleBuffer(Type type, const VkExtent2D& extent, VkFormat format, VkSampleCountFlagBits samples); + MultisampleBuffer(const MultisampleBuffer&) = delete; + MultisampleBuffer& operator=(const MultisampleBuffer&) = delete; + }; + + MultisampleImage(const VkExtent2D& extent, VkFormat format, Mode mode, MultisampleBuffer::Type type); + + VkSampleCountFlagBits chooseSamples(Mode mode); + + const VkSampleCountFlagBits samples; + const MultisampleBuffer buffer; + }; + +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/ImageUsage.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/ImageUsage.h new file mode 100644 index 0000000..34e6c3a --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/ImageUsage.h @@ -0,0 +1,297 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace vlkx { + /** + * Describes how an image (collection of color data) will be used in the GPU. + * Has three parts; an overall description, access methods, and location of access. + * Use the static methods to create an instance, or the blank initializer and set fields as required. + */ + class ImageUsage { + public: + enum class Type { + DontCare, // Image is unused + RenderTarget, // Color attachment is used + DepthStencil, // Depth / Stencil buffer is used + Multisample, // Resolves to a multisampled image + Presentation, // Framebuffer for presentation + LinearAccess, // Host-Readable + InputAttachment, // Only what we write, is read. + Sampled, // Image is sampled (ie. texture) + Transfer // Image is used as an intermediate for transfer. + }; + + enum class Access { + DontCare, // Image is unused + ReadOnly, // Read Only access. + WriteOnly, // Write Only access. + ReadWrite, // Read/Write access. + }; + + enum class Location { + DontCare, // Image is unused + Host, // Image only exists on the host and will be transferred. + VertexShader, // Image is only used in the VertexAll Shader. + FragmentShader, // Image is only used in the Fragment Shader. + ComputeShader, // Image is only used in a Compute Shader. + Other, // Reserved. + }; + + // Sampled in a fragment shader. Read-Only. + static ImageUsage sampledFragment() { return { Type::Sampled, Access::ReadOnly, Location::FragmentShader }; }; + // Used as a render target (a render pass will output to this image). Read/Write. + static ImageUsage renderTarget(int loc) { return { Type::RenderTarget, Access::ReadWrite, Location::Other, loc}; }; + // Resolves to a multisampled image. Write-Only. + static ImageUsage multisample() { return { Type::Multisample, Access::WriteOnly, Location::Other }; }; + // A depth or stencil buffer. Access is given, but must not be DontCare. + static ImageUsage depthStencil(Access acc) { return { Type::DepthStencil, acc, Location::Other}; }; + // Used to show to the user. Write-Only. + static ImageUsage presentation() { return { Type::Presentation, Access::ReadOnly, Location::Other }; }; + // Input attachment for a fragment shader. Usually a texture. Read-Only. + static ImageUsage input() { return { Type::InputAttachment, Access::ReadOnly, Location::FragmentShader }; }; + // Linearly accessed image. For a compute shader. Access is given, but must not be DontCare. + static ImageUsage compute(Access acc) { return { Type::LinearAccess, acc, Location::ComputeShader }; }; + + explicit ImageUsage() : ImageUsage(Type::DontCare, Access::DontCare, Location::DontCare) {} + + bool operator==(const ImageUsage& other) const { + return type == other.type && access == other.access && location == other.location; + } + + VkImageUsageFlagBits getUsageFlags() const { + switch (type) { + case Type::DontCare: throw std::runtime_error("No usage for type DontCare"); + case Type::RenderTarget: + case Type::Multisample: + case Type::Presentation: + return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + case Type::DepthStencil: + return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + case Type::LinearAccess: + return VK_IMAGE_USAGE_STORAGE_BIT; + case Type::Sampled: + return VK_IMAGE_USAGE_SAMPLED_BIT; + case Type::Transfer: + switch (access) { + case Access::DontCare: throw std::runtime_error("No access type specified for transfer usage."); + case Access::ReadOnly: return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + case Access::WriteOnly: return VK_IMAGE_USAGE_TRANSFER_DST_BIT; + case Access::ReadWrite: throw std::runtime_error("ReadWrite access type for Transfer usage is invalid."); + } + } + } + + static VkImageUsageFlags getFlagsForUsage(const std::vector& usages) { + auto flags = 0; + for (const auto& usage : usages) { + if (usage.type != Type::DontCare) + flags |= usage.getUsageFlags(); + } + + return static_cast(flags); + } + + VkImageLayout getLayout() const { + switch (type) { + case Type::DontCare: return VK_IMAGE_LAYOUT_UNDEFINED; + case Type::RenderTarget: + case Type::Multisample: + return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + case Type::DepthStencil: return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + case Type::Presentation: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + case Type::LinearAccess: return VK_IMAGE_LAYOUT_GENERAL; + case Type::Sampled: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + case Type::Transfer: return access == Access::ReadOnly ? VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + case Type::InputAttachment: + break; + } + } + + VkPipelineStageFlags getStage() const { + switch (type) { + case Type::DontCare: return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + case Type::RenderTarget: + case Type::Multisample: + case Type::Presentation: + return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + case Type::DepthStencil: + return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + case Type::LinearAccess: + case Type::Sampled: + switch (location) { + case Location::Host: return VK_PIPELINE_STAGE_HOST_BIT; + case Location::FragmentShader: return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + case Location::ComputeShader: return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + + case Location::VertexShader: + case Location::Other: + throw std::runtime_error("Linear or sampled attachments must not be used in VertexAll or Other stages."); + case Location::DontCare: throw std::runtime_error("Linear or sampled attachments must have an access."); + } + + case Type::Transfer: + return VK_PIPELINE_STAGE_TRANSFER_BIT; + } + } + + Access getAccess() const { return access; } + + Type getType() const { return type; } + + VkAccessFlags getAccessFlags() const { + switch (type) { + case Type::DontCare: return VK_ACCESS_NONE_KHR; + case Type::RenderTarget: return getReadOrWrite(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT); + case Type::DepthStencil: return getReadOrWrite(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT); + case Type::Multisample: return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + case Type::Presentation: return 0; + case Type::LinearAccess: + case Type::Sampled: + return location == Location::Host ? getReadOrWrite(VK_ACCESS_HOST_READ_BIT, VK_ACCESS_HOST_WRITE_BIT) : getReadOrWrite(VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_SHADER_WRITE_BIT); + case Type::Transfer: + return getReadOrWrite(VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT); + case Type::InputAttachment: + return 0; + } + }; + + private: + + ImageUsage(Type t, Access a, Location l, std::optional att = std::nullopt) + : type(t), access(a), location(l), attachment(att) {} + + Type type; + Access access; + Location location; + std::optional attachment; + + inline VkAccessFlags getReadOrWrite(VkAccessFlags read, VkAccessFlags write) const { + VkAccessFlags flag = 0; + if (access == Access::ReadOnly || access == Access::ReadWrite) + flag |= read; + if (access == Access::WriteOnly || access == Access::ReadWrite) + flag |= write; + return flag; + }; + }; + + /** + * Describes how a single image will be used in each stage of a render pass. + * Allows a single image to be written to during one pass, read in a second, and presented in the final, and tracked. + * Helps figure out the optimizations that Vulkan can do to this image and the render passes that use it. + */ + class UsageTracker { + public: + + explicit UsageTracker(const ImageUsage& initial) : initialUsage(initial) {} + explicit UsageTracker() = default; + + UsageTracker(UsageTracker&&) noexcept = default; + UsageTracker& operator=(UsageTracker&&) noexcept = default; + + // Fluent API; chain calls in a builder pattern. + #define fluent UsageTracker& + + fluent add(int pass, const ImageUsage& usage) { + usageAtSubpass.insert( { pass, usage} ); + + return *this; + } + + fluent add(int start, int end, const ImageUsage& usage) { + for (int subpass = start; subpass <= end; ++subpass) + add(subpass, usage); + + return *this; + } + + fluent addMultisample(int pass, std::string_view name) { + multisamples.insert( { pass, std::string(name) } ); + return add(pass, ImageUsage::multisample()); + } + + fluent setFinal(const ImageUsage& usage) { + finalUsage = usage; + return *this; + } + + [[nodiscard]] std::vector getUsages() const { + size_t count = usageAtSubpass.size() + (finalUsage.has_value() ? 1 : 0) + 1; + + std::vector usages; + usages.reserve(count); + usages.emplace_back(initialUsage); + + for(const auto& pair : usageAtSubpass) + usages.emplace_back(pair.second); + + if (finalUsage.has_value()) + usages.emplace_back(finalUsage.value()); + + return usages; + } + + [[nodiscard]] const std::map& getUsageMap() const { + return usageAtSubpass; + } + + ImageUsage& getInitialUsage() { return initialUsage; } + std::optional getFinalUsage() { return finalUsage; } + + + + private: + + std::map usageAtSubpass; + ImageUsage initialUsage; + std::optional finalUsage; + std::map multisamples; + }; + + /** + * A simple wrapper that allows tracking the current usage of multiple images. + */ + class MultiImageTracker { + public: + MultiImageTracker() = default; + + MultiImageTracker(const MultiImageTracker&) = delete; + MultiImageTracker& operator=(const MultiImageTracker&) = delete; + + // Fluent API; chain calls in a builder pattern + #undef fluent + #define fluent MultiImageTracker& + + fluent track(std::string&& name, const ImageUsage& usage) { + images.insert( { std::move(name), usage } ); + return *this; + } + + fluent track(const std::string& name, const ImageUsage& usage) { + return track(std::string(name), usage); + } + + fluent update(const std::string& name, const ImageUsage& usage) { + auto iter = images.find(name); + iter->second = usage; + return *this; + } + + [[nodiscard]] bool isTracking(const std::string& image) const { + return images.contains(image); + } + + [[nodiscard]] const ImageUsage& get(const std::string& image) const { + return images.at(image); + } + + private: + std::map images; + + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Queue.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Queue.h new file mode 100644 index 0000000..ae64d40 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vlkx/vulkan/abstraction/Queue.h @@ -0,0 +1,8 @@ +#pragma once + +namespace vlkx { + struct Queue { + VkQueue queue; + int queueIndex; + }; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/inc/vulkan/vk_mem_alloc.h b/projs/shadow/shadow-engine/shadow-renderer/inc/vulkan/vk_mem_alloc.h index c8a9866..3918862 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/inc/vulkan/vk_mem_alloc.h +++ b/projs/shadow/shadow-engine/shadow-renderer/inc/vulkan/vk_mem_alloc.h @@ -5489,7 +5489,6 @@ public: // Posts next part of an open string. void ContinueString(const char* pStr); // Posts next part of an open string. The number is converted to decimal characters. - void ContinueString(uint32_t n); void ContinueString(uint64_t n); // Posts next part of an open string. Pointer value is converted to characters // using "%p" formatting - shown as hexadecimal number, e.g.: 000000081276Ad00 @@ -5498,7 +5497,6 @@ public: void EndString(const char* pStr = VMA_NULL); // Writes a number value. - void WriteNumber(uint32_t n); void WriteNumber(uint64_t n); // Writes a boolean value - false or true. void WriteBool(bool b); @@ -5654,12 +5652,6 @@ void VmaJsonWriter::ContinueString(const char* pStr) } } -void VmaJsonWriter::ContinueString(uint32_t n) -{ - VMA_ASSERT(m_InsideString); - m_SB.AddNumber(n); -} - void VmaJsonWriter::ContinueString(uint64_t n) { VMA_ASSERT(m_InsideString); @@ -5683,13 +5675,6 @@ void VmaJsonWriter::EndString(const char* pStr) m_InsideString = false; } -void VmaJsonWriter::WriteNumber(uint32_t n) -{ - VMA_ASSERT(!m_InsideString); - BeginValue(false); - m_SB.AddNumber(n); -} - void VmaJsonWriter::WriteNumber(uint64_t n) { VMA_ASSERT(!m_InsideString); diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/Camera.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/Camera.cpp index 2776636..a4544e4 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/src/render/Camera.cpp +++ b/projs/shadow/shadow-engine/shadow-renderer/src/render/Camera.cpp @@ -1,20 +1,129 @@ #include -void Camera::init(float fov, float width, float height, float near, float far) { +using namespace vlkx; - // Initialise members - position = glm::vec3(0, 0, 4); - - glm::vec3 cameraFront = glm::vec3(0, 0, 0); - glm::vec3 cameraUp = glm::vec3(0, 1, 0); - - viewMatrix = glm::mat4(1); - projectionMatrix = glm::mat4(1); - - projectionMatrix = glm::perspective(fov, width / height, near, far); - viewMatrix = glm::lookAt(position, cameraFront, cameraUp); +Camera& Camera::move(const glm::vec3 &delta) { + position += delta; + return *this; } -void Camera::setPosition(glm::vec3 newPosition) { - position = newPosition; -} \ No newline at end of file +Camera &Camera::setPos(const glm::vec3 &pos) { + position = pos; + return *this; +} + +Camera &Camera::up(const glm::vec3 &up) { + upVector = glm::normalize(up); + return *this; +} + +Camera &Camera::forward(const glm::vec3 &forward) { + frontVector = glm::normalize(forward); + rightVector = glm::normalize(glm::cross(frontVector, upVector)); + return *this; +} + +glm::mat4 Camera::getViewMatrix() const { + return glm::lookAt(position, position + frontVector, upVector); +} + +PerspectiveCamera &PerspectiveCamera::fieldOfView(float newFov) { + fov = newFov; + return *this; +} + +PerspectiveCamera::RT PerspectiveCamera::getRT() const { + const glm::vec3 upVec = glm::normalize(glm::cross(getRight(), getForward())); + const float fovTan = glm::tan(glm::radians(fov)); + return { upVec * fovTan, getForward(), getRight() * fovTan * aspectRatio }; +} + +glm::mat4 PerspectiveCamera::getProjMatrix() const { + glm::mat4 proj = glm::perspective(glm::radians(fov), aspectRatio, nearPlane, farPlane); + proj[1][1] = -proj[1][1]; + return proj; +} + +OrthographicCamera &OrthographicCamera::setWidth(float vWidth) { + width = vWidth; + return *this; +} + +glm::mat4 OrthographicCamera::getProjMatrix() const { + const float height = width / aspectRatio; + const auto halfSize = glm::vec2 { width, height } / 2.0f; + return glm::ortho(-halfSize.x, halfSize.x, -halfSize.y, halfSize.y, nearPlane, farPlane); +} + +template +void UserCamera::setInternal(std::function op) { + op(camera.get()); + reset(); +} + +template +void UserCamera::move(double x, double y) { + if (!isActive) return; + + const auto offsetX = static_cast(x * config.turnSpeed); + const auto offsetY = static_cast(y * config.turnSpeed); + + pitch = glm::clamp(pitch - offsetY, glm::radians(-89.9f), glm::radians(89.9f)); + yaw = glm::mod(yaw - offsetX, glm::radians(360.0f)); + camera->forward( { glm::cos(pitch) * glm::cos(yaw), glm::sin(pitch), glm::cos(pitch) * glm::sin(yaw) }); +} + +template +bool UserCamera::scroll(double delta, double min, double max) { + if (!isActive) return false; + + if constexpr (std::is_same_v) { + auto newFov = (float) glm::clamp(camera->getFieldOfView() + delta, min, max); + if (newFov != camera->getFieldOfView()) { + camera->fieldOfView(newFov); + return true; + } + } else if constexpr (std::is_same_v) { + const auto newWidth = (float) glm::clamp(camera->getWidth() + delta, min, max); + if (newWidth != camera->getWidth()) { + camera->setWidth(newWidth); + return true; + } + } else { + static_assert("Unhandled Camera Type"); + } + + return false; +} + +template +void UserCamera::press(Camera::Input key, float time) { + using Key = Camera::Input; + if (!isActive) return; + + if (!config.center.has_value()) { + const float distance = time * config.moveSpeed; + switch (key) { + case Key::Up: + camera->move(+camera->getForward() * distance); break; + case Key::Down: + camera->move(-camera->getForward() * distance); break; + case Key::Left: + camera->move(-camera->getRight() * distance); break; + case Key::Right: + camera->move(+camera->getRight() * distance); break; + } + } else { + reset(); + } +} + +template +void UserCamera::reset() { + refForward = camera->getForward(); + refLeft = -camera->getRight(); + pitch = yaw = 0; +} + +template class vlkx::UserCamera; +template class vlkx::UserCamera; \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/Geometry.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/Geometry.cpp index 89db16e..7358c8b 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/src/render/Geometry.cpp +++ b/projs/shadow/shadow-engine/shadow-renderer/src/render/Geometry.cpp @@ -1,11 +1,11 @@ #include using namespace Geo; -void Mesh::setTriData(std::vector& vertices, std::vector& indices) { - std::vector Vertices = { - { { 0.0f, -1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0, 1.0 } }, - { { 1.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0f, 1.0f, 0.0 },{ 0.0, 0.0 } }, - { { -1.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, +void Mesh::setTriData(std::vector& vertices, std::vector& indices) { + std::vector Vertices = { + { { 0.0f, -1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0, 1.0 } }, + { { 1.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0, 0.0 } }, + { { -1.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, }; std::vector Indices = { @@ -18,13 +18,13 @@ void Mesh::setTriData(std::vector& vertices, std::vector& indi indices = Indices; } -void Mesh::setQuadData(std::vector& vertices, std::vector& indices) { +void Mesh::setQuadData(std::vector& vertices, std::vector& indices) { - std::vector Vertices = { - { { -1.0f, -1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0, 1.0 } }, - { { -1.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0f, 1.0f, 0.0 },{ 0.0, 0.0 } }, - { { 1.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, - { { 1.0f, -1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0f, 0.0f, 1.0 },{ 1.0, 1.0 } } + std::vector Vertices = { + { { -1.0f, -1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0, 1.0 } }, + { { -1.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0, 0.0 } }, + { { 1.0f, 1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, + { { 1.0f, -1.0f, 0.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0, 1.0 } } }; std::vector Indices = { @@ -37,38 +37,38 @@ void Mesh::setQuadData(std::vector& vertices, std::vector& ind indices = Indices; } -void Mesh::setCubeData(std::vector& vertices, std::vector& indices) { - std::vector Vertices = { +void Mesh::setCubeData(std::vector& vertices, std::vector& indices) { + std::vector Vertices = { // Front - { { -1.0f, -1.0f, 1.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0, 1.0 } }, // 0 - { { -1.0f, 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0f, 1.0f, 0.0 },{ 0.0, 0.0 } }, // 1 - { { 1.0f, 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, // 2 - { { 1.0f, -1.0f, 1.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0f, 0.0f, 1.0 },{ 1.0, 1.0 } }, // 3 + { { -1.0f, -1.0f, 1.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0, 1.0 } }, // 0 + { { -1.0f, 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0 },{ 0.0, 0.0 } }, // 1 + { { 1.0f, 1.0f, 1.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, // 2 + { { 1.0f, -1.0f, 1.0f },{ 0.0f, 0.0f, 1.0 },{ 1.0, 1.0 } }, // 3 // Back - { { 1.0, -1.0, -1.0 },{ 0.0f, 0.0f, -1.0 },{ 1.0f, 0.0f, 1.0 },{ 0.0, 1.0 } }, // 4 - { { 1.0f, 1.0, -1.0 },{ 0.0f, 0.0f, -1.0 },{ 0.0f, 1.0f, 1.0 },{ 0.0, 0.0 } }, // 5 - { { -1.0, 1.0, -1.0 },{ 0.0f, 0.0f, -1.0 },{ 0.0f, 1.0f, 1.0 },{ 1.0, 0.0 } }, // 6 - { { -1.0, -1.0, -1.0 },{ 0.0f, 0.0f, -1.0 },{ 1.0f, 0.0f, 1.0 },{ 1.0, 1.0 } }, // 7 + { { 1.0, -1.0, -1.0 },{ 0.0f, 0.0f, -1.0 },{ 0.0, 1.0 } }, // 4 + { { 1.0f, 1.0, -1.0 },{ 0.0f, 0.0f, -1.0 },{ 0.0, 0.0 } }, // 5 + { { -1.0, 1.0, -1.0 },{ 0.0f, 0.0f, -1.0 },{ 1.0, 0.0 } }, // 6 + { { -1.0, -1.0, -1.0 },{ 0.0f, 0.0f, -1.0 },{ 1.0, 1.0 } }, // 7 // Left - { { -1.0, -1.0, -1.0 },{ -1.0f, 0.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 0.0, 1.0 } }, // 8 - { { -1.0f, 1.0, -1.0 },{ -1.0f, 0.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 0.0, 0.0 } }, // 9 - { { -1.0, 1.0, 1.0 },{ -1.0f, 0.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, // 10 - { { -1.0, -1.0, 1.0 },{ -1.0f, 0.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 1.0 } }, // 11 + { { -1.0, -1.0, -1.0 },{ -1.0f, 0.0f, 0.0 },{ 0.0, 1.0 } }, // 8 + { { -1.0f, 1.0, -1.0 },{ -1.0f, 0.0f, 0.0 },{ 0.0, 0.0 } }, // 9 + { { -1.0, 1.0, 1.0 },{ -1.0f, 0.0f, 0.0 },{ 1.0, 0.0 } }, // 10 + { { -1.0, -1.0, 1.0 },{ -1.0f, 0.0f, 0.0 },{ 1.0, 1.0 } }, // 11 // Right - { { 1.0, -1.0, 1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 0.0, 1.0 } }, // 12 - { { 1.0f, 1.0, 1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 0.0, 0.0 } }, // 13 - { { 1.0, 1.0, -1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, // 14 - { { 1.0, -1.0, -1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 1.0 } }, // 15 + { { 1.0, -1.0, 1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0, 1.0 } }, // 12 + { { 1.0f, 1.0, 1.0 },{ 1.0f, 0.0f, 0.0 },{ 0.0, 0.0 } }, // 13 + { { 1.0, 1.0, -1.0 },{ 1.0f, 0.0f, 0.0 },{ 1.0, 0.0 } }, // 14 + { { 1.0, -1.0, -1.0 },{ 1.0f, 0.0f, 0.0 },{ 1.0, 1.0 } }, // 15 // Top - { { -1.0f, 1.0f, 1.0f },{ 0.0f, 1.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 0.0, 1.0 } }, // 16 - { { -1.0f, 1.0f, -1.0f },{ 0.0f, 1.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 0.0, 0.0 } }, // 17 - { { 1.0f, 1.0f, -1.0f },{ 0.0f, 1.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, // 18 - { { 1.0f, 1.0f, 1.0f },{ 0.0f, 1.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 1.0 } }, // 19 + { { -1.0f, 1.0f, 1.0f },{ 0.0f, 1.0f, 0.0 },{ 0.0, 1.0 } }, // 16 + { { -1.0f, 1.0f, -1.0f },{ 0.0f, 1.0f, 0.0 },{ 0.0, 0.0 } }, // 17 + { { 1.0f, 1.0f, -1.0f },{ 0.0f, 1.0f, 0.0 },{ 1.0, 0.0 } }, // 18 + { { 1.0f, 1.0f, 1.0f },{ 0.0f, 1.0f, 0.0 },{ 1.0, 1.0 } }, // 19 // Bottom - { { -1.0f, -1.0, -1.0 },{ 0.0f, -1.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 0.0, 1.0 } }, // 20 - { { -1.0, -1.0, 1.0 },{ 0.0f, -1.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 0.0, 0.0 } }, // 21 - { { 1.0, -1.0, 1.0 },{ 0.0f, -1.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 0.0 } }, // 22 - { { 1.0, -1.0, -1.0 },{ 0.0f, -1.0f, 0.0 },{ 0.0f, 0.0f, 1.0 },{ 1.0, 1.0 } }, // 23 + { { -1.0f, -1.0, -1.0 },{ 0.0f, -1.0f, 0.0 },{ 0.0, 1.0 } }, // 20 + { { -1.0, -1.0, 1.0 },{ 0.0f, -1.0f, 0.0 },{ 0.0, 0.0 } }, // 21 + { { 1.0, -1.0, 1.0 },{ 0.0f, -1.0f, 0.0 },{ 1.0, 0.0 } }, // 22 + { { 1.0, -1.0, -1.0 },{ 0.0f, -1.0f, 0.0 },{ 1.0, 1.0 } }, // 23 }; std::vector Indices = { @@ -97,8 +97,8 @@ void Mesh::setCubeData(std::vector& vertices, std::vector& ind } -void Mesh::setSphereData(std::vector& vertices, std::vector& indices) { - std::vector Vertices; +void Mesh::setSphereData(std::vector& vertices, std::vector& indices) { + std::vector Vertices; std::vector Indices; float latitudeBands = 20.0f; @@ -116,7 +116,7 @@ void Mesh::setSphereData(std::vector& vertices, std::vector& i float sinPhi = sin(phi); float cosPhi = cos(phi); - Vertex vs; + VertexAll vs; vs.texture.x = (longNumber / longitudeBands); // u vs.texture.y = (latNumber / latitudeBands); // v diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/framebuffer/RenderPass.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/framebuffer/RenderPass.cpp deleted file mode 100644 index dfb8cc9..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/src/render/framebuffer/RenderPass.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include - -RenderPass::RenderPass() {} -RenderPass::~RenderPass() {} - - -void RenderPass::createVertexRenderPass(VkFormat format) { - // Set up color metadata - VkAttachmentDescription color = {}; - color.format = format; - color.samples = VK_SAMPLE_COUNT_1_BIT; - color.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - color.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - // Set up subattachments - VkAttachmentReference colorReference = {}; - colorReference.attachment = 0; - colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorReference; - - // Prepare the Render Pass for creation - VkSubpassDependency dependency = {}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - std::array attachments = { color }; - VkRenderPassCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - createInfo.attachmentCount = static_cast(attachments.size()); - createInfo.pAttachments = attachments.data(); - createInfo.subpassCount = 1; - createInfo.dependencyCount = 1; - createInfo.pDependencies = &dependency; - createInfo.pSubpasses = &subpass; - - // Create the Render Pass - if (vkCreateRenderPass(VulkanManager::getInstance()->getDevice()->logical, &createInfo, nullptr, &pass)) - throw std::runtime_error("Unable to create Render Pass 1"); -} - -void RenderPass::beginRenderPass(std::vector clearValues, VkCommandBuffer commands, VkFramebuffer framebuffer, VkExtent2D extent) { - // Prepare the Render Pass for start - VkRenderPassBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - info.renderPass = pass; - info.framebuffer = framebuffer; - - info.renderArea.offset = { 0, 0 }; - info.renderArea.extent = extent; - - info.pClearValues = clearValues.data(); - info.clearValueCount = static_cast(clearValues.size()); - - // Attempt to begin the pass - vkCmdBeginRenderPass(commands, &info, VK_SUBPASS_CONTENTS_INLINE); -} - -void RenderPass::endRenderPass(VkCommandBuffer commands) { - vkCmdEndRenderPass(commands); -} - - -void RenderPass::destroy() { - vkDestroyRenderPass(VulkanManager::getInstance()->getDevice()->logical, pass, nullptr); -} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/geometry/SingleRenderer.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/geometry/SingleRenderer.cpp deleted file mode 100644 index 659de8b..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/src/render/geometry/SingleRenderer.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include - -#include - -void SingleRenderer::createSingleRenderer(Geo::MeshType type, glm::vec3 posIn, glm::vec3 scaleIn) { - - // Collect metadata about the swap chain - uint32_t imageCount = VulkanManager::getInstance()->getSwapchain()->images.size(); - VkExtent2D imageExtent = VulkanManager::getInstance()->getSwapchain()->extent; - - // Create the buffers - buffers.createBuffers(type); - - // Create the descriptor layout - descriptor.createAndAllocateSimple(imageCount); - descriptor.populate(imageCount, buffers.uniformBuffer.buffer, sizeof(Geo::UniformBufferObject)); - - // Create the pipeline - pipeline.create(imageExtent, descriptor.layout, VulkanManager::getInstance()->getRenderPass()->pass); - - // Set locals - position = posIn; - scale = scaleIn; - rotation = glm::mat4_cast(glm::quat(0, 0, 0, 0)); -} - -void SingleRenderer::updateUniforms(Camera camera) { - - // Prepare data to go into the buffers - Geo::UniformBufferObject ubo = {}; - - glm::mat4 scaleMatrix = glm::mat4(1.0f); - glm::mat4 rotationMatrix = getRotation(); - glm::mat4 translationMatrix = glm::mat4(1.0f); - - scaleMatrix = glm::scale(scaleMatrix, scale); - translationMatrix = glm::translate(translationMatrix, position); - - ubo.model = translationMatrix * rotationMatrix * scaleMatrix; - ubo.view = camera.getViewMatrix(); - ubo.proj = camera.getProjectionMatrix(); - - ubo.proj[1][1] *= -1; - - // Copy the buffers into the GPU - void* data; - vmaMapMemory(VulkanManager::getInstance()->getAllocator(), buffers.uniformBuffer.allocation, &data); - memcpy(data, &ubo, sizeof(ubo)); - vmaUnmapMemory(VulkanManager::getInstance()->getAllocator(), buffers.uniformBuffer.allocation); -} - -void SingleRenderer::draw() { - // Fetch the buffer we're going to insert commands to - VkCommandBuffer commands = VulkanManager::getInstance()->getCurrentCommandBuffer(); - - // Bind our pipeline - vkCmdBindPipeline(commands, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline); - - // Bind the vertex buffer - VkBuffer vertexBuffers[] = { - buffers.vertexBuffer.buffer - }; - - VkDeviceSize offsets[] = { - 0 - }; - - vkCmdBindVertexBuffers(commands, 0, 1, vertexBuffers, offsets); - - // Bind the index buffer - vkCmdBindIndexBuffer(commands, buffers.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); - - // Bind the uniform buffer - vkCmdBindDescriptorSets(commands, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 1, &descriptor.set, 0, nullptr); - - // Draw the buffered geometry - vkCmdDrawIndexed(commands, static_cast(buffers.indices.size()), 1, 0, 0, 0); -} - -void SingleRenderer::destroy() { - pipeline.destroy(); - descriptor.destroy(); - buffers.destroy(); -} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/pipeline/Pipeline.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/pipeline/Pipeline.cpp new file mode 100644 index 0000000..42e0165 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/render/pipeline/Pipeline.cpp @@ -0,0 +1,312 @@ +#include "vlkx/render/shader/Pipeline.h" +#include "vlkx/vulkan/VulkanModule.h" +#include "shadow/util/File.h" +#include + +namespace vlkx { + + struct ShaderStage { + VkShaderStageFlagBits stage; + ShaderModule::CountedShader module; + }; + + VkPipelineViewportStateCreateInfo createViewport(const GraphicsPipelineBuilder::Viewport& port) { + return { + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + nullptr, 0, 1, &port.viewport, 1, &port.scissor + }; + } + + VkPipelineColorBlendStateCreateInfo createBlend(const std::vector& states) { + return { + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + nullptr, 0, VK_FALSE, VK_LOGIC_OP_CLEAR, static_cast(states.size()), states.data(), + { 0, 0, 0, 0 } + }; + } + + VkPipelineVertexInputStateCreateInfo createVertexInput(const std::vector& bindingDescs, + const std::vector& attrDescs) { + return { + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + nullptr, 0, + static_cast(bindingDescs.size()), bindingDescs.data(), + static_cast(attrDescs.size()), attrDescs.data() + }; + } + + std::vector createShader(const std::map& shaderMap) { + std::vector stages; + stages.reserve(shaderMap.size()); + for (const auto& pair : shaderMap) { + stages.push_back({ pair.first, ShaderModule::CountedShader::get(pair.second, pair.second) }); + } + + return stages; + } + + std::vector createShaderStage(const std::vector& stages) { + static constexpr char entryPoint[] = "main"; + std::vector infos; + infos.reserve(stages.size()); + for (const auto& stage : stages) { + infos.push_back({ + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, 0, stage.stage, **stage.module, entryPoint, nullptr + }); + } + + return infos; + } + + ShaderModule::ShaderModule(const std::string &path) { + const shadowutil::FileData* file = shadowutil::loadFile(path); + const VkShaderModuleCreateInfo module { + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + nullptr, 0, file->size, reinterpret_cast(file->data.data()) + }; + + if (vkCreateShaderModule(VulkanModule::getInstance()->getDevice()->logical, &module, nullptr, &shader) != VK_SUCCESS) + throw std::runtime_error("Unable to create shader module"); + } + + PipelineBuilder::PipelineBuilder(std::optional maxCache) { + const VkPipelineCacheCreateInfo info { + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, + nullptr, 0, static_cast(maxCache.value_or(0)), nullptr + }; + + if (vkCreatePipelineCache(VulkanModule::getInstance()->getDevice()->logical, &info, nullptr, &cache) != VK_SUCCESS) + throw std::runtime_error("Unable to create pipeline cache"); + } + + void PipelineBuilder::setLayout(std::vector&& descs, + std::vector&& pushConstants) { + std::vector pushSizes (pushConstants.size()); + for (size_t i = 0; i < pushConstants.size(); i++) + pushSizes[i] = pushConstants[i].size; + + const auto totalSize = std::accumulate(pushSizes.begin(), pushSizes.end(), 0); + if (totalSize > 128) + throw std::runtime_error("Trying to set push constants of total size " + std::to_string(totalSize) + " into pipeline " + name); + + descLayouts = std::move(descs); + constants = std::move(pushConstants); + layoutInfo.emplace(VkPipelineLayoutCreateInfo { + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + nullptr, 0, static_cast(descLayouts.size()), descLayouts.data(), + static_cast(constants.size()), constants.data() + }); + } + + GraphicsPipelineBuilder::GraphicsPipelineBuilder(std::optional maxCache) : PipelineBuilder(maxCache) { + assemblyInfo = { + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + nullptr, 0, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE + }; + + rasterizationInfo = { + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + nullptr, 0, VK_FALSE, VK_FALSE, VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, + VK_FALSE, 0, 0, 0, 1 + }; + + multisampleInfo = { + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + nullptr, 0, VK_SAMPLE_COUNT_1_BIT, VK_FALSE, 0, nullptr, VK_FALSE, VK_FALSE + }; + + depthStencilInfo = { + VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + nullptr, 0, VK_FALSE, VK_FALSE, + VK_COMPARE_OP_LESS_OR_EQUAL, VK_FALSE, VK_FALSE, + {}, {}, 0, 1 + }; + + dynamicStateInfo = { + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + nullptr, 0, 0, nullptr + }; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::name(std::string &&name) { + setName(std::move(name)); + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::depthTest(bool enable, bool write) { + depthStencilInfo.depthTestEnable = enable; + depthStencilInfo.depthWriteEnable = write; + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::stencilTest(bool enable) { + depthStencilInfo.stencilTestEnable = enable; + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::multiSample(VkSampleCountFlagBits samples) { + multisampleInfo.rasterizationSamples = samples; + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::topology(VkPrimitiveTopology topology) { + assemblyInfo.topology = topology; + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::stencilOp(const VkStencilOpState &state, + VkStencilFaceFlags flags) { + if (flags & VK_STENCIL_FACE_FRONT_BIT) + depthStencilInfo.front = state; + if (flags & VK_STENCIL_FACE_BACK_BIT) + depthStencilInfo.back = state; + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::addVertex(uint32_t bindPoint, + VkVertexInputBindingDescription &&desc, + std::vector &&attrs) { + desc.binding = bindPoint; + for (auto& attr : attrs) + attr.binding = bindPoint; + bindingDescs.push_back(desc); + + attrDescs.reserve(attrDescs.size() + attrs.size()); + std::move(attrs.begin(), attrs.end(), std::back_inserter(attrDescs)); + attrs.clear(); + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::layout(std::vector &&descLayouts, + std::vector &&constants) { + setLayout(std::move(descLayouts), std::move(constants)); + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::viewport(const vlkx::GraphicsPipelineBuilder::Viewport &port, + bool flipY) { + viewportMeta.emplace(port); + + if (flipY) { + VkViewport& view = viewportMeta.value().viewport; + view.y += view.height; + view.height *= -1; + } + + rasterizationInfo.frontFace = flipY ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::renderPass(const VkRenderPass &pass, uint32_t subpass) { + passMeta.emplace(PassInfo { pass, subpass }); + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::colorBlend( + std::vector &&states) { + blendStates = std::move(states); + return *this; + } + + GraphicsPipelineBuilder& GraphicsPipelineBuilder::shader(VkShaderStageFlagBits stage, std::string &&file) { + shaders[stage] = std::move(file); + return *this; + } + + std::unique_ptr GraphicsPipelineBuilder::build() const { + if (!hasLayout()) + throw std::runtime_error("Pipeline " + getName() + " has no layout set"); + if (!viewportMeta.has_value()) + throw std::runtime_error("Pipeline " + getName() + " has no viewport set"); + if (!passMeta.has_value()) + throw std::runtime_error("Pipeline " + getName() + " has no render pass set"); + if (blendStates.empty()) + throw std::runtime_error("Pipeline " + getName() + " has no color blend states."); + if (shaders.empty()) + throw std::runtime_error("Pipeline " + getName() + " has no shaders bound"); + + const auto viewportState = createViewport(viewportMeta.value()); + const auto blendState = createBlend(blendStates); + const auto vertexState = createVertexInput(bindingDescs, attrDescs); + + const auto shaderStages = createShader(shaders); + const auto shaderStageInfo = createShaderStage(shaderStages); + VkPipelineLayout pipelineLayout; + if (vkCreatePipelineLayout(VulkanModule::getInstance()->getDevice()->logical, &getLayout(), nullptr, &pipelineLayout) != VK_SUCCESS) + throw std::runtime_error("Unable to create layout for pipeline " + getName()); + + const VkGraphicsPipelineCreateInfo createInfo { + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, nullptr, 0, + static_cast(shaderStageInfo.size()), shaderStageInfo.data(), + &vertexState, &assemblyInfo, nullptr, &viewportState, + &rasterizationInfo, &multisampleInfo, &depthStencilInfo, &blendState, &dynamicStateInfo, + pipelineLayout, passMeta->pass, passMeta->subpass, VK_NULL_HANDLE, 0 + }; + + VkPipeline pipeline; + if (vkCreateGraphicsPipelines(VulkanModule::getInstance()->getDevice()->logical, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline) != VK_SUCCESS) + throw std::runtime_error("Failed to create pipeline " + getName()); + + return std::unique_ptr { + new Pipeline(getName(), pipeline, pipelineLayout, VK_PIPELINE_BIND_POINT_GRAPHICS) + }; + } + + ComputePipelineBuilder& ComputePipelineBuilder::name(std::string &&name) { + setName(std::move(name)); + return *this; + } + + ComputePipelineBuilder& ComputePipelineBuilder::layout(std::vector &&descLayouts, + std::vector &&pushConstants) { + setLayout(std::move(descLayouts), std::move(pushConstants)); + return *this; + } + + ComputePipelineBuilder& ComputePipelineBuilder::shader(std::string &&path) { + shaderPath.emplace(std::move(path)); + return *this; + } + + std::unique_ptr ComputePipelineBuilder::build() const { + if (!hasLayout()) + throw std::runtime_error("Pipeline " + getName() + " has no layout set"); + if (!shaderPath.has_value()) + throw std::runtime_error("Pipeline " + getName() + " has no shader set"); + + const auto shaderStages = createShader({{VK_SHADER_STAGE_COMPUTE_BIT, shaderPath.value()}}); + const auto shaderStageInfo = createShaderStage(shaderStages); + if (shaderStageInfo.size() != 1) + throw std::runtime_error("Compute pipeline " + getName() + " must have exactly one shader bound"); + + VkPipelineLayout layout; + if (vkCreatePipelineLayout(VulkanModule::getInstance()->getDevice()->logical, &getLayout(), nullptr, + &layout) != VK_SUCCESS) + throw std::runtime_error("Unable to create layout for compute pipeline " + getName()); + + const VkComputePipelineCreateInfo createInfo{ + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + nullptr, 0, + shaderStageInfo[0], layout, VK_NULL_HANDLE, 0 + }; + + VkPipeline pipeline; + if (vkCreateComputePipelines(VulkanModule::getInstance()->getDevice()->logical, VK_NULL_HANDLE, 1, &createInfo, + nullptr, &pipeline) != VK_SUCCESS) + throw std::runtime_error("Unable to create compute pipeline " + getName()); + + return std::unique_ptr{ + new Pipeline{getName(), pipeline, layout, VK_PIPELINE_BIND_POINT_COMPUTE} + }; + } + + void Pipeline::bind(const VkCommandBuffer &buffer) const { + vkCmdBindPipeline(buffer, bindPoint, pipeline); + } + + Pipeline::~Pipeline() { + vkDestroyPipeline(VulkanModule::getInstance()->getDevice()->logical, pipeline, nullptr); + vkDestroyPipelineLayout(VulkanModule::getInstance()->getDevice()->logical, layout, nullptr); + } +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/GPUPass.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/GPUPass.cpp new file mode 100644 index 0000000..c516451 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/GPUPass.cpp @@ -0,0 +1,394 @@ +#include "vlkx/render/render_pass/GPUPass.h" + +namespace vlkx { + + inline bool needsSynchronization(const ImageUsage& prev, const ImageUsage& curr) { + if (curr == prev && curr.getAccess() == ImageUsage::Access::ReadOnly) + return false; + return true; + } + + void addUsageToSubpass(const ImageUsage& usage, RenderPassBuilder::SubpassDependency::SubpassMeta* pass) { + pass->stage |= usage.getStage(); + pass->access |= usage.getAccessFlags(); + } + + void CommonPass::addUsage(std::string &&name, UsageTracker &&tracker) { + for (const auto& pair : tracker.getUsageMap()) + validate(pair.first, name, false); + + tracker.add(getVirtualInitial(), tracker.getInitialUsage()); + if (tracker.getFinalUsage().has_value()) + tracker.add(getVirtualFinal(), tracker.getFinalUsage().value()); + + usageHistory.emplace(std::move(name), std::move(tracker)); + } + + VkImageLayout CommonPass::getInitialLayout(const std::string &name) const { + return getHistory(name).getUsageMap().begin()->second.getLayout(); + } + + VkImageLayout CommonPass::getFinalLayout(const std::string &name) const { + return getHistory(name).getUsageMap().rbegin()->second.getLayout(); + } + + VkImageLayout CommonPass::getSubpassLayout(const std::string &name, int subpass) const { + validate(subpass, name, false); + return getUsage(name, subpass)->getLayout(); + } + + void CommonPass::update(const std::string &name, MultiImageTracker &tracker) const { + tracker.update(name, getHistory(name).getUsageMap().rbegin()->second); + } + + const UsageTracker& CommonPass::getHistory(const std::string &name) const { + return usageHistory.at(name); + } + + const ImageUsage* CommonPass::getUsage(const std::string &name, int pass) const { + validate(pass, name, true); + const UsageTracker& history = getHistory(name); + const auto iter = history.getUsageMap().find(pass); + return iter != history.getUsageMap().end() ? &iter->second : nullptr; + } + + std::optional CommonPass::checkForSync(const std::string &name, int pass) const { + validate(pass, name, true); + const UsageTracker& history = getHistory(name); + const auto currIter = history.getUsageMap().find(pass); + if (currIter == history.getUsageMap().end()) + return std::nullopt; + const auto prevIter = std::prev(currIter); + + const ImageUsage& prevUsage = prevIter->second; + const ImageUsage& currUsage = currIter->second; + + if (!needsSynchronization(prevUsage, currUsage)) + return std::nullopt; + + const int prevSubpass = prevIter->first; + return CommonPass::Usages { prevSubpass, &prevUsage, &currUsage }; + } + + void CommonPass::validate(int pass, const std::string &image, bool includeVirtual) const { + if (includeVirtual) { + if (!(pass >= getVirtualInitial() && pass <= getVirtualFinal())) + throw std::runtime_error("Subpass out of range."); + } else { + if (!(pass >= 0 && pass < numPasses)) + throw std::runtime_error("nv Subpass out of range."); + } + } + + int GraphicsPass::add(const std::string &name, UsageTracker &&history, std::function &&getter, + const std::optional ops) { + verifyHistory(name, history); + + const std::optional needsGetter = getFirstRenderTarget(history); + if (needsGetter.has_value()) { + if (getter == nullptr) + throw std::runtime_error("Image " + name + " is used as a render target without a location getter."); + } else { + getter = nullptr; + } + + const int attachmentLocation = static_cast(metas.size()); + metas.insert( + { + name, + AttachmentMeta { + attachmentLocation, + std::move(getter), + getOps(name, history, ops), + {} + }, + } + ); + + addUsage(std::string(name), std::move(history)); + return attachmentLocation; + } + + GraphicsPass& GraphicsPass::addMultisample(const std::string &source, const std::string &dest, int pass) { + validate(pass, source, false); + + const auto source_iter = usageHistory.find(source); + if (source_iter == usageHistory.end()) + throw std::runtime_error("Usage history not found for source image " + source); + + const UsageTracker& source_history = source_iter->second; + if (!verifyImageUsage(source_history, pass, ImageUsage::Type::RenderTarget)) + throw std::runtime_error("Usage type for source image " + source + " must be render target."); + + const auto dest_iter = usageHistory.find(dest); + if (dest_iter == usageHistory.end()) + throw std::runtime_error("Usage history not found for destination image " + dest); + + const UsageTracker& dest_history = dest_iter->second; + if (!verifyImageUsage(dest_history, pass, ImageUsage::Type::Multisample)) + throw std::runtime_error("Usage type for destination image " + dest + " must be multisample"); + + auto& targetMap = metas[source].multisample; + const bool inserted = targetMap.insert( { pass, dest }).second; + + if (!inserted) + throw std::runtime_error("Image " + source + " is already bound to a multisample."); + + return *this; + } + + void GraphicsPass::setAttachments() { + for (const auto& pair : usageHistory) { + const std::string& name = pair.first; + const AttachmentMeta& meta = metas[name]; + builder->setAttachment(meta.index, { meta.ops, getInitialLayout(name), getFinalLayout(name) } ); + } + } + + void GraphicsPass::setSubpasses() { + for (int pass = 0; pass < numPasses; ++pass) { + std::vector colors; + std::vector multisamples; + VkAttachmentReference dsRef { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED }; + + // Verify all images used, the long way around. + for (const auto& pair : usageHistory) { + const std::string& name = pair.first; + const ImageUsage* history = getUsage(name, pass); + if (history == nullptr) + continue; + + const AttachmentMeta& meta = metas[name]; + const VkAttachmentReference ref { static_cast(meta.index), history->getLayout() }; + + switch (history->getType()) { + // If we're looking at a render target, we need to figure out where it gets its' details from. + case ImageUsage::Type::RenderTarget: { + const int location = meta.getter(pass); + const auto iter = meta.multisample.find(pass); + if (iter != meta.multisample.end()) { + const std::string& target = iter->second; + const ImageUsage* targetUsage = getUsage(target, pass); + if (targetUsage == nullptr) + throw std::runtime_error("Expected target image to have a usage"); + multisamples.push_back( { location, metas[target].index, targetUsage->getLayout() }); + } + + colors.push_back( { location, static_cast(ref.attachment), ref.layout }); + + break; + } + + case ImageUsage::Type::DepthStencil: + if (dsRef.attachment != VK_ATTACHMENT_UNUSED) + throw std::runtime_error("Depth stencil used multiple times"); + dsRef = ref; + break; + + case ImageUsage::Type::Multisample: + break; + + default: + throw std::runtime_error("Unreachable?"); + } + } + + auto colorRefs = RenderPassBuilder::parseColorReferences(colors); + auto multisampleRefs = RenderPassBuilder::parseMutisampling(colorRefs.size(), multisamples); + builder->setSubpass(pass, std::move(colorRefs), std::move(multisampleRefs), dsRef); + } + } + + void GraphicsPass::setDependencies() { + if (getVirtualFinal() != numPasses) + throw std::runtime_error("Virtual subpass mismatch"); + for (int pass = 0; pass <= numPasses; ++pass) { + std::map deps; + + for (const auto& pair : usageHistory) { + const auto usage = checkForSync(pair.first, pass); + if (!usage.has_value()) continue; + + const ImageUsage& prev = usage.value().lastUsage; + const ImageUsage& curr = usage.value().currentUsage; + const int sourcePass = usage.value().lastSubpass; + + auto iter = deps.find(sourcePass); + if (iter == deps.end()) { + const RenderPassBuilder::SubpassDependency defaultDep { + { checkSubpass(sourcePass), VK_PIPELINE_STAGE_NONE_KHR, VK_ACCESS_NONE_KHR }, + { checkSubpass(pass), VK_PIPELINE_STAGE_NONE_KHR, VK_ACCESS_NONE_KHR }, + 0 + }; + + iter = deps.insert( { sourcePass, defaultDep } ).first; + } + + addUsageToSubpass(prev, &iter->second.source); + addUsageToSubpass(curr, &iter->second.destination); + } + + for (const auto& pair : deps) { + const RenderPassBuilder::SubpassDependency& dep = pair.second; + builder->addDependency(dep); + } + } + } + + std::unique_ptr GraphicsPass::build(int framebuffers) { + builder = std::make_unique(); + builder->setFramebufferCount(framebuffers); + + setAttachments(); + setSubpasses(); + setDependencies(); + return std::move(builder); + } + + std::optional GraphicsPass::getFirstRenderTarget(const UsageTracker &history) const { + for (const auto& pair : history.getUsageMap()) { + const int pass = pair.first; + if (isVirtual(pass)) continue; + + if (pair.second.getType() == ImageUsage::Type::RenderTarget) return pass; + } + + return std::nullopt; + } + + RenderPassBuilder::Attachment::OpsType GraphicsPass::getOps(const std::string &name, const UsageTracker &history, + const std::optional &userOps) const { + const ImageUsage::Type type = getUsageType(name, history); + + if (!userOps.has_value()) { + switch (type) { + case ImageUsage::Type::RenderTarget: return getDefaultOps(); + case ImageUsage::Type::DepthStencil: return getStencilOps(); + default: + throw std::runtime_error("Unreachable?"); + } + } + + const RenderPassBuilder::Attachment::OpsType& ops = userOps.value(); + switch (type) { + case ImageUsage::Type::RenderTarget: + case ImageUsage::Type::DepthStencil: + return ops; + default: + throw std::runtime_error("Unreachable?"); + } + } + + ImageUsage::Type GraphicsPass::getUsageType(const std::string &name, const UsageTracker &history) const { + ImageUsage::Type prev = ImageUsage::Type::DontCare; + + for (const auto& pair : history.getUsageMap()) { + if (isVirtual(pair.first)) continue; + + ImageUsage::Type type = pair.second.getType(); + if (type == ImageUsage::Type::Multisample) + type = ImageUsage::Type::RenderTarget; + + if (prev == ImageUsage::Type::DontCare) { + prev = type; + } else if (type != prev) { + throw std::runtime_error("Inconsistent usage type specified for " + name); + } + } + + if (prev == ImageUsage::Type::DontCare) + throw std::runtime_error("Image " + name + " has no usages."); + + return prev; + } + + bool GraphicsPass::verifyImageUsage(const UsageTracker &history, int subpass, ImageUsage::Type type) const { + const auto iter = history.getUsageMap().find(subpass); + return iter != history.getUsageMap().end() && iter->second.getType() == type; + } + + void GraphicsPass::verifyHistory(const std::string &image, const UsageTracker &history) const { + for (const auto& pair : history.getUsageMap()) { + const ImageUsage::Type type = pair.second.getType(); + if (type != ImageUsage::Type::RenderTarget && type != ImageUsage::Type::DepthStencil && type != ImageUsage::Type::Multisample) + throw std::runtime_error("Invalid usage of " + image + " at subpass " + std::to_string(pair.first)); + } + } + + ComputePass &ComputePass::add(std::string &&name, UsageTracker &&history) { + verify(name, history); + addUsage(std::move(name), std::move(history)); + return *this; + } + + void ComputePass::execute(const VkCommandBuffer &commands, uint32_t queueFamily, + const std::map &images, + const std::vector>& computeOps) const { + + if (computeOps.size() != numPasses) + throw std::runtime_error("Compute shader mismatches ops and passes."); + + if (getVirtualFinal() != numPasses) + throw std::runtime_error("Compute shader attempting to run too many subpasses"); + + for (int pass = 0; pass < numPasses; ++pass) { + for (const auto& pair : usageHistory) { + const std::string& image = pair.first; + const auto usage = checkForSync(image, pass); + if (!usage.has_value()) continue; + + const auto iter = images.find(image); + if (iter == images.end()) + throw std::runtime_error("Image " + image + " not provided"); + + barrier(commands, queueFamily, *iter->second, usage.value().lastUsage, usage.value().currentUsage); + } + + if (pass < numPasses) + computeOps[pass](); + } + } + + void ComputePass::barrier(const VkCommandBuffer &commands, uint32_t queueFamily, const VkImage &image, + const ImageUsage &prev, const ImageUsage ¤t) const { + const VkImageMemoryBarrier barrier { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + nullptr, + prev.getAccessFlags(), + current.getAccessFlags(), + prev.getLayout(), + current.getLayout(), + queueFamily, + queueFamily, + image, + { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, + 1, + 0, + 1 + } + }; + + vkCmdPipelineBarrier( + commands, + prev.getStage(), + current.getStage(), + 0, + 0, + nullptr, + 0, + nullptr, + 1, + &barrier + ); + } + + void ComputePass::verify(const std::string &name, const UsageTracker &history) const { + for (const auto& pair : history.getUsageMap()) { + const ImageUsage::Type type = pair.second.getType(); + if (type != ImageUsage::Type::LinearAccess && type != ImageUsage::Type::Sampled && type != ImageUsage::Type::Transfer) + throw std::runtime_error("Compute shader using an attachment that is not guranteed to be readable."); + } + } +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/GenericRenderPass.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/GenericRenderPass.cpp new file mode 100644 index 0000000..302a00d --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/GenericRenderPass.cpp @@ -0,0 +1,268 @@ +#include "vlkx/render/render_pass/GenericRenderPass.h" +#include +#include +#include "vlkx/vulkan/VulkanModule.h" +#include + +namespace vlkx { + + /** + * Creates the necessary Clear Value struct to erase the given attachment. + * @param attachment the attachment metadata + * @return the Clear Value that will erase the attachment's data + */ + VkClearValue createClearFor(const RenderPassBuilder::Attachment& attachment) { + + VkClearValue clear {}; + if (std::holds_alternative(attachment.ops)) + clear.color = { { 0, 0, 0, 0 } }; + else { + clear.depthStencil = { 1.0, 0 }; + } + + return clear; + } + + /** + * Convert a RenderPassBuilder attachment to a VkAttachmentDescription. + * Format will be UNDEFINED. + * Sample count will be 1. + */ + VkAttachmentDescription buildAttachment(const RenderPassBuilder::Attachment& attachment) { + VkAttachmentDescription descriptor { + {}, + VK_FORMAT_UNDEFINED, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + attachment.layoutInitial, + attachment.layoutFinal + }; + + if (const auto& ops = std::get_if(&attachment.ops); ops != nullptr) { + descriptor.loadOp = ops->LOAD; + descriptor.storeOp = ops->STORE; + } else if (const auto& ops = std::get_if(&attachment.ops); ops != nullptr) { + descriptor.loadOp = ops->DEPTH_LOAD; + descriptor.storeOp = ops->DEPTH_STORE; + descriptor.stencilLoadOp = ops->STENCIL_LOAD; + descriptor.stencilStoreOp = ops->STENCIL_STORE; + } + + return descriptor; + } + + std::vector buildSubpassDescriptors(const std::vector& attachments) { + std::vector descriptors; + descriptors.reserve(attachments.size()); + + for (const auto& attachment : attachments) { + descriptors.emplace_back(VkSubpassDescription { + {}, + VK_PIPELINE_BIND_POINT_GRAPHICS, + 0, + nullptr, + static_cast(attachment.colorReferences.size()), + attachment.colorReferences.data(), + attachment.multisampleReferences.empty() ? nullptr : attachment.multisampleReferences.data(), + attachment.stencilDepthReference.has_value() ? &attachment.stencilDepthReference.value() : nullptr, + 0, + nullptr + } + ); + } + + return descriptors; + } + + VkSubpassDependency buildSubpassDependency(const RenderPassBuilder::SubpassDependency& dep) { + return VkSubpassDependency { + dep.source.index, + dep.destination.index, + dep.source.stage, + dep.destination.stage, + dep.source.access, + dep.destination.access, + dep.flags + }; + } + + std::vector countColorAttachments(const std::vector& attachments) { + std::vector count; + count.reserve(attachments.size()); + + for (const auto& attachment : attachments) + count.emplace_back(attachment.colorReferences.size()); + + return count; + } + + std::vector createFramebuffers(const VkRenderPass& renderPass, const std::vector> getters, int count, const VkExtent2D& extent) { + std::vector views(getters.size()); + + VkFramebufferCreateInfo framebufferCreate { + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + nullptr, + {}, + renderPass, + static_cast(views.size()), + views.data(), + extent.width, + extent.height, + 1 + }; + + std::vector framebuffers(count); + for (int i = 0; i < framebuffers.size(); ++i) { + for (int image = 0; image < getters.size(); image++) + views[image] = getters[image](i).getView(); + + vkCreateFramebuffer(VulkanModule::getInstance()->getDevice()->logical, &framebufferCreate, nullptr, &framebuffers[i]); + } + + return framebuffers; + } + + std::vector RenderPassBuilder::parseColorReferences(std::vector meta) { + if (meta.empty()) + return {}; + + // Search for the highest location index'd attachment reference. + // Shaders can define negative locations, so we have to start as low as we can go, + // and work our way up until we find the highest. + // If we start at 0, we risk missing an all-negative location set. + int max = std::numeric_limits::min(); + for (const auto& attachment : meta) + max = std::max(max, attachment.location); + + std::vector references(max + 1, { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED }); + for (const auto& attachment : meta) + references[attachment.location] = { static_cast(attachment.descriptionIdx), attachment.layout }; + + return references; + } + + std::vector RenderPassBuilder::parseMutisampling(int colorReferencesCount, std::vector meta) { + std::vector references(colorReferencesCount, { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED }); + for (const auto& attachment : meta) + references[attachment.location] = { static_cast(attachment.descriptionIdx), attachment.layout }; + + return references; + } + + fluent RenderPassBuilder::setFramebufferCount(int count) { + framebufferCount = count; + return *this; + } + + fluent RenderPassBuilder::setAttachment(int idx, const Attachment &attachment) { + if (idx > clearValues.size()) + clearValues.resize(idx + 1); + clearValues.at(idx) = createClearFor(attachment); + + if (idx > attachmentDescriptors.size()) + attachmentDescriptors.resize(idx + 1); + attachmentDescriptors.at(idx) = buildAttachment(attachment); + + if (attachmentDescriptors.size() > attachmentGetters.size()) + attachmentGetters.resize(attachmentDescriptors.size()); + + return *this; + } + + fluent RenderPassBuilder::updateAttachmentBacking(int idx, + std::function &&getBacking) { + const Image& img = getBacking(idx); + attachmentDescriptors[idx].format = img.getFormat(); + attachmentDescriptors[idx].samples = img.getSamples(); + attachmentGetters.at(idx) = std::move(getBacking); + return *this; + } + + fluent RenderPassBuilder::setSubpass(int idx, std::vector &&color, + std::vector &&multisample, + VkAttachmentReference &depthStencil) { + if (multisample.empty()) + if (multisample.size() != color.size()) + throw std::runtime_error("Constructing a subpass with mismatched color and multisample attachments"); + + SubpassAttachments attachments { + std::move(color), std::move(multisample), depthStencil + }; + + subpassAttachments.emplace_back(attachments); + return *this; + } + + fluent RenderPassBuilder::addDependency(const SubpassDependency &dep) { + subpassDependencies.emplace_back(buildSubpassDependency(dep)); + return *this; + } + + std::unique_ptr RenderPassBuilder::build() const { + if (framebufferCount == 0) + throw std::runtime_error("No framebuffers in render pass"); + for (int i = 0; i < attachmentGetters.size(); i++) + if (attachmentGetters[i] == nullptr) + throw std::runtime_error("Image " + std::to_string(i) + " is not set in render pass"); + + const auto descriptors = buildSubpassDescriptors(subpassAttachments); + const VkRenderPassCreateInfo createInfo { + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + nullptr, + {}, + static_cast(attachmentDescriptors.size()), + attachmentDescriptors.data(), + static_cast(descriptors.size()), + descriptors.data(), + static_cast(subpassDependencies.size()), + subpassDependencies.data() + }; + + VkRenderPass pass; + if (vkCreateRenderPass(VulkanModule::getInstance()->getDevice()->logical, &createInfo, nullptr, &pass) != VK_SUCCESS) + throw std::runtime_error("Unable to create render pass"); + + const auto framebufferSize = attachmentGetters[0](0).getExtent(); + + return std::make_unique ( + static_cast(descriptors.size()), pass, clearValues, framebufferSize, createFramebuffers(pass, attachmentGetters, framebufferCount.value(), framebufferSize), + countColorAttachments(subpassAttachments) + ); + } + + void RenderPass::execute(const VkCommandBuffer &commands, int imageIndex, + std::vector> ops) const { + const VkRenderPassBeginInfo begin { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + nullptr, + renderPass, + framebuffers[imageIndex], + { + {0, 0}, + extent + }, + static_cast(clearValues.size()), + clearValues.data() + }; + + vkCmdBeginRenderPass(commands, &begin, VK_SUBPASS_CONTENTS_INLINE); + + for (int i = 0; i < ops.size(); i++) { + if (i != 0) + vkCmdNextSubpass(commands, VK_SUBPASS_CONTENTS_INLINE); + ops[i](commands); + } + + vkCmdEndRenderPass(commands); + } + + RenderPass::~RenderPass() { + for (const auto& fb : framebuffers) + vkDestroyFramebuffer(VulkanModule::getInstance()->getDevice()->logical, fb, nullptr); + vkDestroyRenderPass(VulkanModule::getInstance()->getDevice()->logical, renderPass, nullptr); + } + +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/ScreenRenderPass.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/ScreenRenderPass.cpp new file mode 100644 index 0000000..0b3775d --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/render/render_pass/ScreenRenderPass.cpp @@ -0,0 +1,145 @@ +#include "vlkx/render/render_pass/ScreenRenderPass.h" +#include "vlkx/vulkan/abstraction/Image.h" +#include "vlkx/render/render_pass/GPUPass.h" +#include "vlkx/vulkan/VulkanModule.h" + +namespace vlkx { + + void checkSubpass(int pass, int high) { if (pass < 1 || pass > high) throw std::runtime_error("Subpass index too high"); } + + void addAttachment(const AttachmentConfig& config, GraphicsPass& pass, MultiImageTracker& tracker, GraphicsPass::LocationGetter&& getter, const std::function& populateHistory) { + const std::string& name = config.name; + if (!tracker.isTracking(name)) + throw std::runtime_error("Attempting to add image " + name + " that is not tracked"); + + UsageTracker history { tracker.get(name) }; + populateHistory(history); + + if (config.finalUsage.has_value()) + history.setFinal(config.finalUsage.value()); + + config.index = pass.add(name, std::move(history), std::move(getter), config.loadStoreOps); + pass.update(name, tracker); + } + + RendererConfig::RendererConfig(int passCount, std::vector>& destinations, bool toScreen, std::optional firstTransparent, std::optional firstOverlay) : renderImages(destinations) { + if (passCount < 1) + throw std::runtime_error("Creating a RendererConfig with less than 1 subpass."); + + if (firstTransparent.has_value()) + checkSubpass(firstTransparent.value(), passCount); + if (firstOverlay.has_value()) + checkSubpass(firstOverlay.value(), passCount); + + if (firstOverlay.has_value()) + numOverlayPasses = passCount - firstOverlay.value(); + if (firstTransparent.has_value()) { + numOpaquePasses = firstTransparent.value(); + numTransparentPasses = passCount - numOpaquePasses - numOverlayPasses; + } else { + numOpaquePasses = passCount - numOverlayPasses; + } + + rendersToScreen = toScreen; + } + + std::unique_ptr SimpleRenderPass::createBuilder(int framebuffers, + const vlkx::RendererConfig &config, + const vlkx::AttachmentConfig &color, + const vlkx::AttachmentConfig *multisample, + const vlkx::AttachmentConfig *depthStencil, + vlkx::MultiImageTracker &tracker) { + const int passes = config.passes(); + const int firstPass = 0; + const int lastPass = passes - 1; + + const auto getLocation = [](int pass) { return 0; }; + bool usesMultisample = multisample != nullptr; + bool usesDepth = depthStencil != nullptr; + + const bool passesUsingDepth = config.depthPasses() > 0; + + if (usesDepth) { + if (passesUsingDepth == 0) + throw std::runtime_error("Depth stencil defined, but never used."); + } else + if (passesUsingDepth > 0) + throw std::runtime_error("Depth stencil used, but never defined."); + + GraphicsPass graphicsPass(passes); + + addAttachment(color, graphicsPass, tracker, getLocation, [&](UsageTracker& history) { + if (usesMultisample) + history.add(lastPass, ImageUsage::multisample()); + else + history.add(firstPass, lastPass, ImageUsage::renderTarget(0)); + }); + + if (usesMultisample) { + addAttachment(*multisample, graphicsPass, tracker, getLocation, [&](UsageTracker& history) { + history.add(firstPass, lastPass, ImageUsage::renderTarget(0)); + }); + graphicsPass.addMultisample(multisample->name, color.name, lastPass); + } + + if (usesDepth) + addAttachment(*depthStencil, graphicsPass, tracker, getLocation, [&](UsageTracker& history) { + if (config.numOpaquePasses > 0) { + const int lastOpaque = config.numOpaquePasses - 1; + history.add(firstPass, lastOpaque, ImageUsage::depthStencil(ImageUsage::Access::ReadWrite)); + } + + if (config.numTransparentPasses > 0) { + const int firstTransparent = config.numOpaquePasses; + const int lastTransparent = firstTransparent + config.numTransparentPasses - 1; + history.add(firstTransparent, lastTransparent, ImageUsage::depthStencil(ImageUsage::Access::ReadOnly)); + } + }); + + return graphicsPass.build(framebuffers); + + } + + void ScreenRenderPassManager::initializeRenderPass() { + if (config.usesDepth()) { + depthStencilImage = MultisampleImage::createDepthStencil(VulkanModule::getInstance()->getSwapchain()->extent, std::nullopt); + } + + if (passBuilder == nullptr) + preparePassBuilder(); + + passBuilder->updateAttachmentBacking(destinationInfo.index.value(), [this](int index) -> const Image& { + return *config.renderImages[index]; + }); + + if (depthStencilImage != nullptr) + passBuilder->updateAttachmentBacking(depthStencilInfo.index.value(), [this](int index) -> const Image& { + return *depthStencilImage; + }); + + pass = passBuilder->build(); + } + + void ScreenRenderPassManager::preparePassBuilder() { + const bool usesDepth = depthStencilImage != nullptr; + const bool usesMultisampling = false; + + MultiImageTracker tracker; + destinationInfo.add(tracker, *config.renderImages[0]); + if (usesDepth) + depthStencilInfo.add(tracker, *depthStencilImage); + if (usesMultisampling) + // TODO + (void) 0; + + auto colorConfig = destinationInfo.makeConfig(); + if (config.rendersToScreen) + colorConfig.setUsage(ImageUsage::presentation()); + else + colorConfig.setUsage(ImageUsage::sampledFragment()); + const auto multisampleConfig = multisampleInfo.makeConfig(); + const auto depthConfig = depthStencilInfo.makeConfig(); + + passBuilder = SimpleRenderPass::createBuilder(config.renderImages.size(), config, colorConfig, usesMultisampling ? &multisampleConfig : nullptr, usesDepth ? &depthConfig : nullptr, tracker); + } +} diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/Descriptor.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/Descriptor.cpp deleted file mode 100644 index 9ec96f7..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/Descriptor.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include -#include -#include - -#include - -Descriptor::Descriptor() {} -Descriptor::~Descriptor() {} - -void Descriptor::createAndAllocateSimple(uint32_t images) { - createSimpleLayout(); - createSimplePool(images); -} - -void Descriptor::createSimpleLayout() { - // Set up a binding - VkDescriptorSetLayoutBinding binding = {}; - binding.binding = 0; - binding.descriptorCount = 1; - binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - - // Prepare to create the layout - std::array bindings = { - binding - }; - - VkDescriptorSetLayoutCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - info.bindingCount = static_cast(bindings.size()); - info.pBindings = bindings.data(); - - // Create the layout - if (vkCreateDescriptorSetLayout(VulkanManager::getInstance()->getDevice()->logical, &info, nullptr, &layout) != VK_SUCCESS) - throw std::runtime_error("Unable to create Descriptor layout"); -} - -void Descriptor::createSimplePool(uint32_t images) { - // Set the size of the pool we want - VkDescriptorPoolSize size = {}; - size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - size.descriptorCount = images; - - std::array sizes = { - size - }; - - // Prepare to create the pool - VkDescriptorPoolCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - createInfo.poolSizeCount = static_cast(sizes.size()); - createInfo.pPoolSizes = sizes.data(); - createInfo.maxSets = images; - - // Create the pool - if (vkCreateDescriptorPool(VulkanManager::getInstance()->getDevice()->logical, &createInfo, nullptr, &pool) != VK_SUCCESS) - throw std::runtime_error("Unable to create Descriptor pool"); - - // Prepare to allocate the set - std::vector layouts(images, layout); - VkDescriptorSetAllocateInfo allocateInfo = {}; - allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocateInfo.descriptorPool = pool; - allocateInfo.descriptorSetCount = images; - allocateInfo.pSetLayouts = layouts.data(); - - // Allocate the Set - if (vkAllocateDescriptorSets(VulkanManager::getInstance()->getDevice()->logical, &allocateInfo, &set) != VK_SUCCESS) - throw std::runtime_error("Unable to allocate Descriptor set"); -} - -void Descriptor::populate(uint32_t images, VkBuffer uniforms, size_t bufferSize) { - // Iterate images - for (size_t i = 0; i < images; i++) { - // Set up the uniform buffer - VkDescriptorBufferInfo buffer = {}; - buffer.buffer = uniforms; - buffer.offset = 0; - buffer.range = bufferSize; - - // Prepare to write the buffer into the Descriptor set - VkWriteDescriptorSet write = {}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.pNext = nullptr; - write.dstSet = set; - write.dstBinding = 0; - write.dstArrayElement = 0; - write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - write.descriptorCount = 1; - write.pBufferInfo = &buffer; - write.pImageInfo = nullptr; - write.pTexelBufferView = nullptr; - - std::array writes = { - write - }; - - // Write the buffer into the descriptor - vkUpdateDescriptorSets(VulkanManager::getInstance()->getDevice()->logical, static_cast(writes.size()), writes.data(), 0, nullptr); - } -} - -void Descriptor::destroy() { - vkDestroyDescriptorPool(VulkanManager::getInstance()->getDevice()->logical, pool, nullptr); - vkDestroyDescriptorSetLayout(VulkanManager::getInstance()->getDevice()->logical, layout, nullptr); -} - -VkDescriptorSetLayout createBindingWrapper(std::vector bindings) { - VkDescriptorSetLayoutCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - info.bindingCount = static_cast(bindings.size()); - info.pBindings = bindings.data(); - - VkDescriptorSetLayout layout; - - // Create the layout - if (vkCreateDescriptorSetLayout(VulkanManager::getInstance()->getDevice()->logical, &info, nullptr, &layout) != VK_SUCCESS) - throw std::runtime_error("Unable to create Descriptor layout"); - - return layout; -} -VkDescriptorPool createPoolWrapper(std::vector sizes, uint32_t images) { - // Prepare to create the pool - VkDescriptorPoolCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - createInfo.poolSizeCount = static_cast(sizes.size()); - createInfo.pPoolSizes = sizes.data(); - createInfo.maxSets = images; - - VkDescriptorPool pool; - - // Create the pool - if (vkCreateDescriptorPool(VulkanManager::getInstance()->getDevice()->logical, &createInfo, nullptr, &pool) != VK_SUCCESS) - throw std::runtime_error("Unable to create Descriptor pool"); - - return pool; -} diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/GeoBuffers.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/GeoBuffers.cpp deleted file mode 100644 index 0664cc4..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/GeoBuffers.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include -#include - -GeoBuffers::GeoBuffers() {} -GeoBuffers::~GeoBuffers() {} - -void GeoBuffers::createBuffers(Geo::MeshType type) { - // Set vertex and indice data - switch (type) { - case Geo::MeshType::Triangle: - Geo::Mesh::setTriData(vertices, indices); - break; - case Geo::MeshType::Quad: - Geo::Mesh::setQuadData(vertices, indices); - break; - case Geo::MeshType::Cube: - Geo::Mesh::setCubeData(vertices, indices); - break; - case Geo::MeshType::Sphere: - Geo::Mesh::setSphereData(vertices, indices); - break; - } - - // Create buffers - createVertexBuffer(); - createIndexBuffer(); - createUniformBuffer(); -} - -void GeoBuffers::createVertexBuffer() { - // Gather the size of the buffer we need.. - VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - - // Create and bind a temporary buffer - VkTools::ManagedBuffer staging = VkTools::createGPUBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VulkanManager::getInstance()->getDevice()->logical, VulkanManager::getInstance()->getDevice()->physical); - - // Get ready to write into our GPU buffer - void* data; - vmaMapMemory(VulkanManager::getInstance()->getAllocator(), staging.allocation, &data); - - // Copy vertex data into the buffer - memcpy(data, vertices.data(), (size_t)bufferSize); - - // Unmap the buffer from stack space - vmaUnmapMemory(VulkanManager::getInstance()->getAllocator(), staging.allocation); - - // Prepare an area in the GPU that we cannot see, that the vertex data can live permanently. - vertexBuffer = VkTools::createGPUBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VulkanManager::getInstance()->getDevice()->logical, VulkanManager::getInstance()->getDevice()->physical, false); - - // Copy our data from the staging buffer into the new permanent buffer - VkTools::copyGPUBuffer(staging.buffer, vertexBuffer.buffer, bufferSize, VulkanManager::getInstance()->getDevice()->logical, VulkanManager::getInstance()->getDevice()->graphicsQueue, VulkanManager::getInstance()->getDevice()->queueData.graphics); - - // Cleanup the staging area. - vmaDestroyBuffer(VulkanManager::getInstance()->getAllocator(), staging.buffer, staging.allocation); -} - -void GeoBuffers::createIndexBuffer() { - // Gather the size of the buffer we need.. - VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - - // Create and bind a temporary buffer - VkTools::ManagedBuffer staging = VkTools::createGPUBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VulkanManager::getInstance()->getDevice()->logical, VulkanManager::getInstance()->getDevice()->physical); - - // Get ready to write into our GPU buffer - void* data; - vmaMapMemory(VulkanManager::getInstance()->getAllocator(), staging.allocation, &data); - - // Copy index data into the buffer - memcpy(data, indices.data(), (size_t)bufferSize); - - // Unmap the buffer from stack space - vmaUnmapMemory(VulkanManager::getInstance()->getAllocator(), staging.allocation); - - // Prepare an area in the GPU that we cannot see, that the vertex data can live permanently. - indexBuffer = VkTools::createGPUBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VulkanManager::getInstance()->getDevice()->logical, VulkanManager::getInstance()->getDevice()->physical); - - // Copy our data from the staging buffer into the new permanent buffer - VkTools::copyGPUBuffer(staging.buffer, indexBuffer.buffer, bufferSize, VulkanManager::getInstance()->getDevice()->logical, VulkanManager::getInstance()->getDevice()->graphicsQueue, VulkanManager::getInstance()->getDevice()->queueData.graphics); - - // Cleanup the staging area. - vmaDestroyBuffer(VulkanManager::getInstance()->getAllocator(), staging.buffer, staging.allocation); -} - -void GeoBuffers::createUniformBuffer() { - // Allocate a buffer of the right size - we don't need to copy uniforms. - VkDeviceSize bufferSize = sizeof(Geo::UniformBufferObject); - - uniformBuffer = VkTools::createGPUBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VulkanManager::getInstance()->getDevice()->logical, VulkanManager::getInstance()->getDevice()->physical); -} - -void GeoBuffers::destroy() { - // Cleanup uniform buffers - vmaDestroyBuffer(VulkanManager::getInstance()->getAllocator(), uniformBuffer.buffer, uniformBuffer.allocation); - - // Cleanup index buffers - vmaDestroyBuffer(VulkanManager::getInstance()->getAllocator(), indexBuffer.buffer, indexBuffer.allocation); - - // Cleanup vertex buffers - vmaDestroyBuffer(VulkanManager::getInstance()->getAllocator(), vertexBuffer.buffer, vertexBuffer.allocation); -} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/Pipeline.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/Pipeline.cpp deleted file mode 100644 index ed37569..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/src/render/shader/Pipeline.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include -#include - -#include -#include -#include - -Pipeline::Pipeline() {} -Pipeline::~Pipeline() {} - -void Pipeline::create(VkExtent2D extent, VkDescriptorSetLayout set, VkRenderPass renderPass) { - createPipelineLayout(set); - createVertexPipeline(extent, renderPass); -} - -void Pipeline::createPipelineLayout(VkDescriptorSetLayout set) { - // Prepare to create the pipeline layout - VkPipelineLayoutCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - info.setLayoutCount = 1; - info.pSetLayouts = &set; - - // Create the layout - if (vkCreatePipelineLayout(VulkanManager::getInstance()->getDevice()->logical, &info, nullptr, &layout) != VK_SUCCESS) - throw std::runtime_error("Unable to create Pipeline Layout."); -} - -std::vector Pipeline::readFile(const std::string& filename) { - // Prepare the stream for reading the file - std::ifstream file(filename, std::ios::ate | std::ios::binary); - - if (!file.is_open()) - throw std::runtime_error(std::string("Unable to open shader file: ").append(filename)); - - size_t fileSize = (size_t)file.tellg(); - - // Read the file into a vector - std::vector buffer(fileSize); - file.seekg(0); - file.read(buffer.data(), fileSize); - file.close(); - - return buffer; -} - -VkShaderModule Pipeline::createShaderModule(const std::vector& code) { - // Prepare to create the shader module - VkShaderModuleCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - info.codeSize = code.size(); - info.pCode = reinterpret_cast(code.data()); - - // Create the module - VkShaderModule shaderModule; - if (vkCreateShaderModule(VulkanManager::getInstance()->getDevice()->logical, &info, nullptr, &shaderModule) != VK_SUCCESS) - throw std::runtime_error("Unable to create Shader module from SPIR-V binary"); - - return shaderModule; -} - -void Pipeline::createVertexPipeline(VkExtent2D extent, VkRenderPass renderPass) { - - // ------- Stage: Shader ------- // - - // Read the vertex shader - auto vertexShaderCode = readFile("vlkx-resources/shader/SPIRV/basic.vert.spv"); - VkShaderModule vertexShaderModule = createShaderModule(vertexShaderCode); - - // Prepare to create the Shader Stage - VkPipelineShaderStageCreateInfo vertexShaderCreateInfo = {}; - vertexShaderCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vertexShaderCreateInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; - vertexShaderCreateInfo.module = vertexShaderModule; - vertexShaderCreateInfo.pName = "main"; - - - // Read the fragment shader - auto fragmentShaderCode = readFile("vlkx-resources/shader/SPIRV/basic.frag.spv"); - VkShaderModule fragmentShaderModule = createShaderModule(fragmentShaderCode); - - // Prepare to create the Shader Stage - VkPipelineShaderStageCreateInfo fragmentShaderCreateInfo = {}; - fragmentShaderCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - fragmentShaderCreateInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - fragmentShaderCreateInfo.module = fragmentShaderModule; - fragmentShaderCreateInfo.pName = "main"; - - VkPipelineShaderStageCreateInfo shaderStages[] = { - vertexShaderCreateInfo, - fragmentShaderCreateInfo - }; - - // ------- Stage: Shader Input ------- // - - auto bindingDescription = Geo::Vertex::getBindingDesc(); - auto attributeDescription = Geo::Vertex::getAttributeDesc(); - - VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo = {}; - vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputCreateInfo.vertexBindingDescriptionCount = 1; - vertexInputCreateInfo.pVertexBindingDescriptions = &bindingDescription; - vertexInputCreateInfo.vertexAttributeDescriptionCount = static_cast(attributeDescription.size()); - vertexInputCreateInfo.pVertexAttributeDescriptions = attributeDescription.data(); - - // ------- Stage: Input Assembly ------- // - - VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo = {}; - inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - inputAssemblyCreateInfo.primitiveRestartEnable = VK_FALSE; - - // ------- Stage: Rasterization ------- // - - VkPipelineRasterizationStateCreateInfo rasterCreateInfo = {}; - rasterCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterCreateInfo.depthClampEnable = VK_FALSE; - rasterCreateInfo.rasterizerDiscardEnable = VK_FALSE; - rasterCreateInfo.polygonMode = VK_POLYGON_MODE_FILL; - rasterCreateInfo.lineWidth = 1.0f; - rasterCreateInfo.cullMode = VK_CULL_MODE_BACK_BIT; - rasterCreateInfo.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterCreateInfo.depthBiasEnable = VK_FALSE; - rasterCreateInfo.depthBiasConstantFactor = 0.0f; - rasterCreateInfo.depthBiasClamp = 0.0f; - rasterCreateInfo.depthBiasSlopeFactor = 0.0f; - - // ------- Stage: MultiSample ------- // - - VkPipelineMultisampleStateCreateInfo multisampleCreateInfo = {}; - multisampleCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampleCreateInfo.sampleShadingEnable = VK_FALSE; - multisampleCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - // ------- Stage: Color Blending ------- // - - VkPipelineColorBlendAttachmentState colorBlendAttach = {}; - colorBlendAttach.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorBlendAttach.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo colorBlendCreateInfo = {}; - colorBlendCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendCreateInfo.attachmentCount = 1; - colorBlendCreateInfo.pAttachments = &colorBlendAttach; - - // ------- Stage: Viewport ------- // - - VkViewport viewport = {}; - viewport.x = 0; - viewport.y = 0; - viewport.width = (float)extent.width; - viewport.height = (float)extent.height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = { 0, 0 }; - scissor.extent = extent; - - VkPipelineViewportStateCreateInfo viewportCreateInfo = {}; - viewportCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportCreateInfo.viewportCount = 1; - viewportCreateInfo.pViewports = &viewport; - viewportCreateInfo.scissorCount = 1; - viewportCreateInfo.pScissors = &scissor; - - // ------- Create the Pipeline ------- // - - VkGraphicsPipelineCreateInfo pipelineInfo = {}; - pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipelineInfo.stageCount = 2; - pipelineInfo.pStages = shaderStages; - - pipelineInfo.pVertexInputState = &vertexInputCreateInfo; - pipelineInfo.pInputAssemblyState = &inputAssemblyCreateInfo; - pipelineInfo.pRasterizationState = &rasterCreateInfo; - pipelineInfo.pMultisampleState = &multisampleCreateInfo; - pipelineInfo.pDepthStencilState = nullptr; - pipelineInfo.pColorBlendState = &colorBlendCreateInfo; - pipelineInfo.pDynamicState = nullptr; - pipelineInfo.pViewportState = &viewportCreateInfo; - - pipelineInfo.layout = layout; - pipelineInfo.renderPass = renderPass; - pipelineInfo.subpass = 0; - - if (vkCreateGraphicsPipelines(VulkanManager::getInstance()->getDevice()->logical, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline) != VK_SUCCESS) - throw std::runtime_error("Unable to create a Vertex rendering Pipeline."); - - - // ------- Cleanup temporary allocations ------- // - - vkDestroyShaderModule(VulkanManager::getInstance()->getDevice()->logical, vertexShaderModule, nullptr); - vkDestroyShaderModule(VulkanManager::getInstance()->getDevice()->logical, fragmentShaderModule, nullptr); -} - - -void Pipeline::destroy() { - vkDestroyPipeline(VulkanManager::getInstance()->getDevice()->logical, pipeline, nullptr); - vkDestroyPipelineLayout(VulkanManager::getInstance()->getDevice()->logical, layout, nullptr); -} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/render/texture/RenderTexture.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/render/texture/RenderTexture.cpp deleted file mode 100644 index e340453..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/src/render/texture/RenderTexture.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include - -SingleRenderTexture::SingleRenderTexture() {} -SingleRenderTexture::~SingleRenderTexture() {} - -void SingleRenderTexture::createViewsAndFramebuffer(std::vector images, VkFormat format, VkExtent2D extent, VkRenderPass pass) { - // Initialize members - this->swapChainImages = images; - this->swapChainImageExtent = extent; - - createViews(format); - createFramebuffer(extent, pass); -} - -void SingleRenderTexture::createViews(VkFormat format) { - // Prepare maximum size - swapChainImageViews.resize(swapChainImages.size()); - - // Iterate images and create views for each. - for (size_t i = 0; i < swapChainImages.size(); i++) { - swapChainImageViews[i] = VkTools::createImageView(swapChainImages[i], format, VK_IMAGE_ASPECT_COLOR_BIT, VulkanManager::getInstance()->getDevice()->logical); - } -} - -void SingleRenderTexture::createFramebuffer(VkExtent2D extent, VkRenderPass pass) { - // Prepare maximum size - swapChainFramebuffers.resize(swapChainImageViews.size()); - - // Iterate views and create a framebuffer for each. - for (size_t i = 0; i < swapChainImageViews.size(); i++) { - // Create an array with the image view as an attachment. - std::array attachments = { - swapChainImageViews[i] - }; - - // Prepare the creation of a new framebuffer. - // One attachment, width and height from the extent, and one layer (one viewport) - VkFramebufferCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - info.renderPass = pass; - info.attachmentCount = static_cast(attachments.size()); - info.pAttachments = attachments.data(); - info.width = extent.width; - info.height = extent.height; - info.layers = 1; - - // Create the framebuffer - if (vkCreateFramebuffer(VulkanManager::getInstance()->getDevice()->logical, &info, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) - throw std::runtime_error("Unable to create framebuffer for a texture."); - } -} - -void SingleRenderTexture::destroy() { - // Destroy Image Views first - for (auto imageView : swapChainImageViews) { - vkDestroyImageView(VulkanManager::getInstance()->getDevice()->logical, imageView, nullptr); - } - - // Framebuffers - for (auto framebuffer : swapChainFramebuffers) { - vkDestroyFramebuffer(VulkanManager::getInstance()->getDevice()->logical, framebuffer, nullptr); - } - -} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/temp/model/Builder.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/temp/model/Builder.cpp new file mode 100644 index 0000000..5ae383b --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/temp/model/Builder.cpp @@ -0,0 +1,238 @@ +#include "temp/model/Builder.h" + +namespace vlkxtemp { + using namespace vlkx; + using Geo::VertexAll; + using VertexData = PerVertexBuffer::NoShareMeta; + + std::unique_ptr createTex(const ModelBuilder::TextureSource& source) { + const auto usages = { ImageUsage::sampledFragment() }; + return std::make_unique(source, usages, ImageSampler::Config {}); + } + + void fillTextureMeta(const ModelBuilder::BindingPoints& binding, const ModelBuilder::TexturePerMesh& textures, const ModelBuilder::TexturePerMesh& sharedTextures, Descriptor::Meta* meta, Descriptor::ImageInfos* infos) { + *meta = {Image::getSampleType(), VK_SHADER_STAGE_FRAGMENT_BIT, {} }; + auto& texBindings = meta->bindings; + + for (size_t idx = 0; idx < (size_t) ModelBuilder::TextureType::Count; idx++) { + const auto type = (ModelBuilder::TextureType) idx; + const size_t numTextures = textures[idx].size() + sharedTextures[idx].size(); + if (numTextures != 0) { + const auto iter = binding.find(type); + if (iter == binding.end()) + throw std::runtime_error("Binding point of texture type " + std::to_string(idx) + " is not set"); + + texBindings.push_back({ iter->second, static_cast(numTextures) }); + + auto& metaMap = (*infos)[iter->second]; + metaMap.reserve(numTextures); + for (const auto& texture : textures[idx]) + metaMap.push_back(texture->getInfoForSampling()); + for (const auto& texture : sharedTextures[idx]) + metaMap.push_back(texture->getInfoForSampling()); + } + } + } + + std::vector createRanges(const ModelBuilder::ModelPushConstant& constants) { + std::vector ranges; + ranges.reserve(constants.constants.size()); + for (const auto& meta : constants.constants) + ranges.push_back( { constants.stage, meta.offset, meta.constants->getSize() }); + return ranges; + } + + VkVertexInputBindingDescription getBinding(uint32_t stride, bool instancing) { + return VkVertexInputBindingDescription{ 0, stride,instancing ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX, }; + } + + void setVertexInput(const PerVertexBuffer& buffer, const std::vector& instanceBuffers, GraphicsPipelineBuilder* builder) { + uint32_t start = 0; + auto attributes = buffer.getAttrs(start); + start += attributes.size(); + + builder->addVertex(0, Geo::VertexAll::getBindingDesc(), std::move(attributes)); + + for (size_t i = 0; i < instanceBuffers.size(); i++) { + if (instanceBuffers[i] == nullptr) + throw std::runtime_error("PerInstanceVertexBuffer not specified"); + auto instanceAttrs = instanceBuffers[i]->getAttrs(start); + start += instanceAttrs.size(); + + auto instanceBinding = getBinding(instanceBuffers[i]->getSize(), true); + builder->addVertex(i + 1, std::move(instanceBinding), std::move(instanceAttrs)); + } + } + + void ModelBuilder::SingleMeshModel::load(ModelBuilder* builder) const { + const Wavefront obj(objFile, objIndexBase); + VertexData vertices { + {{ + PerVertexBuffer::VertexDataMeta { obj.indices }, + PerVertexBuffer::VertexDataMeta { obj.vertices } + }} + }; + + builder->vertexBuffer = std::make_unique(std::move(vertices), Geo::VertexAll::getAttributeDesc()); + + auto& meshTexs = builder->textures; + meshTexs.push_back({}); + for (const auto& pair : textureSources) { + const auto type = (size_t)pair.first; + const auto& sources = pair.second; + + meshTexs.back()[type].reserve(sources.size()); + for (const auto& source : sources) + meshTexs.back()[type].push_back({createTex(source)}); + } + } + + void ModelBuilder::MultiMeshModel::load(ModelBuilder* builder) const { + const ModelLoader loader(models, textures); + std::vector data; + data.reserve(loader.getMeshes().size()); + + for (const auto& mesh : loader.getMeshes()) + data.push_back({ PerVertexBuffer::VertexDataMeta { mesh.indices }, PerVertexBuffer::VertexDataMeta { mesh.vertices } }); + + builder->vertexBuffer = std::make_unique(VertexData { std::move(data)}, Geo::VertexAll::getAttributeDesc()); + + const auto usages = { ImageUsage::sampledFragment() }; + auto& meshTexs = builder->textures; + meshTexs.reserve(loader.getMeshes().size()); + for (const auto& mesh : loader.getMeshes()) { + meshTexs.push_back({}); + for (const auto& tex : mesh.textures) + meshTexs.back()[(size_t) tex.type].push_back(std::make_unique(tex.path, usages, ImageSampler::Config {})); + } + } + + ModelBuilder::ModelBuilder(std::string &&name, int frames, float aspect, const ModelResource &resource) + : frames(frames), aspectRatio(aspect), uniformBufferMeta(frames), pipelineBuilder(std::make_unique()) { + pipelineBuilder->name(std::move(name)); + resource.load(this); + } + + ModelBuilder& ModelBuilder::texture(TextureType type, const TextureSource &source) { + sharedTextures[(size_t) type].push_back(createTex(source)); + return *this; + } + + ModelBuilder& ModelBuilder::bindTextures(TextureType type, uint32_t point) { + bindPoints[type] = point; + return *this; + } + + ModelBuilder& ModelBuilder::instanceBuffer(vlkx::PerInstanceVertexBuffer* buffer) { + instanceBuffers.push_back(buffer); + return *this; + } + + ModelBuilder& ModelBuilder::uniform(VkShaderStageFlags stage, std::vector &&bindings) { + uniformMeta.push_back({ UniformBuffer::getDescriptorType(), stage, std::move(bindings) }); + return *this; + } + + ModelBuilder& ModelBuilder::uniformBuffer(uint32_t point, const vlkx::UniformBuffer &buffer) { + for (size_t frame = 0; frame < frames; frame++) { + const int chunk = buffer.isSingle() ? 0 : frame; + uniformBufferMeta[frame][point].push_back( buffer.getDescriptorInfo(chunk) ); + } + + return *this; + } + + ModelBuilder& ModelBuilder::pushStage(VkShaderStageFlags stage) { + if (!pushConstants.has_value()) + pushConstants.emplace(); + + pushConstants->stage = stage; + return *this; + } + + ModelBuilder& ModelBuilder::pushConstant(const vlkx::PushConstant* constant, uint32_t offset) { + if (!pushConstants.has_value()) + pushConstants.emplace(); + + pushConstants.value().constants.push_back( ModelPushConstant::Meta { constant, offset }); + return *this; + } + + ModelBuilder& ModelBuilder::shader(VkShaderStageFlagBits stage, std::string &&file) { + pipelineBuilder->shader(stage, std::move(file)); + return *this; + } + + std::vector ModelBuilder::createDescs() const { + std::vector descs(frames); + auto infos = uniformMeta; + infos.resize(infos.size() + 1); + + for (size_t frame = 0; frame < frames; frame++) { + descs[frame].reserve(textures.size()); + + for (const auto& tex : textures) { + Descriptor::ImageInfos image; + fillTextureMeta(bindPoints, tex, sharedTextures, &infos.back(), &image); + + descs[frame].push_back(std::make_unique(infos)); + descs[frame].back()->buffers(UniformBuffer::getDescriptorType(), uniformBufferMeta[frame]); + descs[frame].back()->images(Image::getSampleType(), image); + } + } + + return descs; + } + + std::unique_ptr ModelBuilder::build() { + if (pushConstants.has_value()) + if (pushConstants->constants.empty()) + throw std::runtime_error("Model sets push constant present but no data."); + + auto descs = createDescs(); + pipelineBuilder->layout( + { descs[0][0]->getLayout() }, + pushConstants.has_value() ? createRanges(pushConstants.value()) : std::vector {} + ); + + setVertexInput(*vertexBuffer, instanceBuffers, pipelineBuilder.get()); + + uniformMeta.clear(); + uniformBufferMeta.clear(); + + return std::unique_ptr { + new Model { + aspectRatio, std::move(vertexBuffer), std::move(instanceBuffers), std::move(pushConstants), + std::move(sharedTextures), std::move(textures), std::move(descs), std::move(pipelineBuilder) + } + }; + } + + void Model::update(bool opaque, const VkExtent2D &frame, VkSampleCountFlagBits samples, + const vlkx::RenderPass &pass, uint32_t subpass, bool flipY) { + + pipeline = (*pipelineBuilder) + .depthTest(true, opaque) + .multiSample(samples) + .viewport({ { 0, 0, static_cast(frame.width), static_cast(frame.height), 0, 1 }, { { 0, 0 }, frame } }) + .renderPass(*pass, subpass) + .colorBlend(std::vector(pass.getAttachsInSubpass(subpass), vlkx::Pipeline::getAlphaBlendState(!opaque))) + .build(); + } + + void Model::draw(const VkCommandBuffer &commands, int frame, uint32_t instances) const { + pipeline->bind(commands); + + for (size_t i = 0; i < perInstanceBuffers.size(); i++) + perInstanceBuffers[i]->bind(commands, i + 1, 0); + + if (pushConstants.has_value()) + for (const auto& meta : pushConstants->constants) + meta.constants->upload(commands, pipeline->getLayout(), frame, meta.offset, pushConstants->stage); + + for (size_t mesh = 0; mesh < textures.size(); mesh++) { + descriptors[frame][mesh]->bind(commands, pipeline->getLayout(), pipeline->getBind()); + vertexBuffer->draw(commands, 0, mesh, instances); + } + } +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/temp/model/Loader.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/temp/model/Loader.cpp new file mode 100644 index 0000000..17cf42e --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/temp/model/Loader.cpp @@ -0,0 +1,96 @@ +#include "temp/model/Loader.h" +#include +#include +#include +#include +#include + +namespace vlkxtemp { + + std::vector split (std::string_view s, char delim) { + std::vector result; + std::stringstream ss ((std::string(s))); + std::string item; + + while (std::getline (ss, item, delim)) { + result.push_back (item); + } + + return result; + } + + Wavefront::Wavefront(std::string_view path, size_t index_base) { + std::ifstream file(std::string(path), std::ios::binary); + + std::vector positions; + std::vector normals; + std::vector tex_coords; + std::map loaded_vertices; + + const auto parse_line = [&](std::string_view line) { + const size_t non_space = line.find_first_not_of(' '); + if (non_space == std::string::npos || line[0] == '#') + return; + + switch (line[non_space]) { + case 'v': { + switch (line[non_space + 1]) { + case ' ': { + const auto nums = split(line.substr(non_space + 2), ' '); + positions.emplace_back(stof(nums[0]), stof(nums[1]), stof(nums[2])); + break; + } + case 'n': { + // Normal. + const auto nums = split(line.substr(non_space + 3), ' '); + normals.emplace_back(glm::vec3{stof(nums[0]), stof(nums[1]), stof(nums[2])}); + break; + } + case 't': { + // Texture coordinates. + const auto nums = split(line.substr(non_space + 3), ' '); + tex_coords.emplace_back(glm::vec2{stof(nums[0]), stof(nums[1])}); + break; + } + default: + throw std::runtime_error("Unexpected symbol " + std::to_string(line[non_space + 1])); + } + break; + } + case 'f': { + for (const auto& seg : split(line.substr(non_space + 2), ' ')) { + const auto iter = loaded_vertices.find(seg); + if (iter != loaded_vertices.end()) { + indices.push_back(iter->second); + } else { + indices.push_back(vertices.size()); + loaded_vertices[seg] = vertices.size(); + const auto idxs = split(seg, '/'); + vertices.push_back(Geo::VertexAll { + positions.at(stoi(idxs[0]) - index_base), + normals.at(stoi(idxs[2]) - index_base), + tex_coords.at(stoi(idxs[1]) - index_base), + }); + } + } + break; + } + default: + throw std::runtime_error("Unexpected symbol in OBJ file: " + std::to_string(line[non_space])); + } + }; + + std::string line; + int line_num = 1; + try { + for (; std::getline(file, line); ++line_num) + parse_line(line); + } catch (const std::exception& e) { + throw std::runtime_error("Failed to parse obj file, error on line " + std::to_string(line_num) + ": " + line + "; " + e.what()); + } + } + + ModelLoader::ModelLoader(const std::string &model, const std::string &textures) { + + } +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/CommandBuffer.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/CommandBuffer.cpp index 00cf528..e69de29 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/CommandBuffer.cpp +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/CommandBuffer.cpp @@ -1,60 +0,0 @@ -#include -#include - -CommandBuffer::CommandBuffer() {} -CommandBuffer::~CommandBuffer() {} - -void CommandBuffer::createCommandPoolAndBuffers(size_t size) { - createCommandPool(); - allocateCommandBuffers(size); -} - -void CommandBuffer::createCommandPool() { - // Prepare queues - QueueFamilies families = VulkanManager::getInstance()->getDevice()->getQueues(); - - // Prepare command pool creation data - VkCommandPoolCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - info.queueFamilyIndex = families.graphics; - info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - - // Attempt creation - if (vkCreateCommandPool(VulkanManager::getInstance()->getDevice()->logical, &info, nullptr, &commands) != VK_SUCCESS) - throw std::runtime_error("Unable to create a command pool."); -} - -void CommandBuffer::allocateCommandBuffers(size_t size) { - // Prepare allocation info - buffers.resize(size); - - VkCommandBufferAllocateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - info.commandPool = commands; - info.commandBufferCount = (uint32_t)buffers.size(); - - // Attempt allocation - if (vkAllocateCommandBuffers(VulkanManager::getInstance()->getDevice()->logical, &info, buffers.data()) != VK_SUCCESS) - throw std::runtime_error("Unable to allocate command buffer"); -} - -void CommandBuffer::beginCommandBuffer(VkCommandBuffer buffer) { - // Prepare to begin listening on this buffer - VkCommandBufferBeginInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; // Allow writing to this buffer while another is being read. - - // Attempt to begin listening - if (vkBeginCommandBuffer(buffer, &info) != VK_SUCCESS) - throw std::runtime_error("Unable to begin a command buffer"); -} - -void CommandBuffer::endCommandBuffer(VkCommandBuffer buffer) { - // Attempt to end listening - if (vkEndCommandBuffer(buffer) != VK_SUCCESS) - throw std::runtime_error("Unable to end listening for a command buffer"); -} - -void CommandBuffer::destroy() { - vkDestroyCommandPool(VulkanManager::getInstance()->getDevice()->logical, commands, nullptr); -} diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/SwapChain.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/SwapChain.cpp index 600198e..d48d28b 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/SwapChain.cpp +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/SwapChain.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "spdlog/spdlog.h" SwapChain::SwapChain() {} @@ -45,7 +45,7 @@ VkExtent2D SwapChain::chooseExtent(const VkSurfaceCapabilitiesKHR& capabilities) } void SwapChain::create(VkSurfaceKHR surface) { - SwapChainMeta info = VulkanManager::getInstance()->getDevice()->swapChain; + SwapChainMeta info = VulkanModule::getInstance()->getDevice()->swapChain; VkSurfaceFormatKHR chosenFormat = chooseFormat(info.formats); VkPresentModeKHR chosenMode = chooseMode(info.modes); @@ -66,7 +66,7 @@ void SwapChain::create(VkSurfaceKHR surface) { createInfo.imageArrayLayers = 1; // 2 for VR createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - QueueFamilies queues = VulkanManager::getInstance()->getDevice()->getQueues(); + QueueFamilies queues = VulkanModule::getInstance()->getDevice()->getQueues(); uint32_t indices[] = { static_cast(queues.graphics), static_cast(queues.presentation) }; if (queues.graphics != queues.presentation) { @@ -86,19 +86,32 @@ void SwapChain::create(VkSurfaceKHR surface) { createInfo.oldSwapchain = VK_NULL_HANDLE; // Create the swap-chain - if (vkCreateSwapchainKHR(VulkanManager::getInstance()->getDevice()->logical, &createInfo, nullptr, &swapChain)) + if (vkCreateSwapchainKHR(VulkanModule::getInstance()->getDevice()->logical, &createInfo, nullptr, &swapChain)) throw std::runtime_error("Failed to create swap-chain"); - // Fetch our images from the swapchain - vkGetSwapchainImagesKHR(VulkanManager::getInstance()->getDevice()->logical, swapChain, &imageCount, nullptr); - images.resize(imageCount); - vkGetSwapchainImagesKHR(VulkanManager::getInstance()->getDevice()->logical, swapChain, &imageCount, images.data()); + // Set members + format = chosenFormat.format; + extent = chosenExtent; + + // Fetch our images from the swapchain + + uint32_t swapchainImgCount = 0; + vkGetSwapchainImagesKHR(VulkanModule::getInstance()->getDevice()->logical, swapChain, &swapchainImgCount, nullptr); + + std::vector swapchainImgs(swapchainImgCount); + vkGetSwapchainImagesKHR(VulkanModule::getInstance()->getDevice()->logical, swapChain, &swapchainImgCount, swapchainImgs.data()); + + images.resize(0); + images.reserve(imageCount); + for (const auto& img : swapchainImgs) { + images.emplace_back(std::make_unique(img, extent, format)); + } - // Set gloabls - format = chosenFormat.format; - extent = chosenExtent; } void SwapChain::destroy() { - vkDestroySwapchainKHR(VulkanManager::getInstance()->getDevice()->logical, swapChain, nullptr); + vkDestroySwapchainKHR(VulkanModule::getInstance()->getDevice()->logical, swapChain, nullptr); + /*for (auto & image : images) + image.reset(); + multisampleImg.reset(); */ } \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/Tools.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/Tools.cpp new file mode 100644 index 0000000..50cc3c9 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/Tools.cpp @@ -0,0 +1,123 @@ +#include +#include +#include "vlkx/vulkan/abstraction/Commands.h" + +API VmaAllocator VkTools::allocator; + +VkTools::ManagedImage VkTools::createImage(VkFormat format, VkImageUsageFlags flags, VkExtent3D extent) { + // Set up image metadata + VkImageCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + info.imageType = VK_IMAGE_TYPE_3D; + info.pNext = nullptr; + info.format = format; + info.extent = extent; + info.mipLevels = 1; + info.arrayLayers = 1; + info.samples = VK_SAMPLE_COUNT_1_BIT; + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = flags; + + // Prepare the managed image + ManagedImage image {}; + + // Set up image allocation + VmaAllocationCreateInfo allocateInfo = {}; + allocateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + + // Allocate + create the image + vmaCreateImage(allocator, &info, &allocateInfo, &image.image, &image.allocation, nullptr); + + return image; +} + +VkSampler VkTools::createSampler(VkFilter filters, VkSamplerAddressMode mode, uint32_t mipping, VkDevice dev) { + VkSamplerCreateInfo info = { + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + nullptr, {}, filters, filters, + VK_SAMPLER_MIPMAP_MODE_LINEAR, mode, mode, mode, + 0, VK_TRUE, 16, VK_FALSE, + VK_COMPARE_OP_ALWAYS, 0, static_cast(mipping), + VK_BORDER_COLOR_INT_OPAQUE_BLACK, VK_FALSE + }; + + VkSampler sampler; + vkCreateSampler(dev, &info, nullptr, &sampler); + + return sampler; +} + +VkImageView VkTools::createImageView(VkImage image, VkFormat format, VkImageAspectFlags flags, uint32_t mipping, uint32_t layers, VkDevice device) { + // Raw information about the image + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = image; + viewInfo.viewType = layers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_CUBE; + viewInfo.format = format; + + // Information about the things we want to create - size, mip levels. + viewInfo.subresourceRange.aspectMask = flags; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = mipping; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = layers; + + VkImageView imageView; + if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) + throw std::runtime_error("Failed to create texture image view."); + + return imageView; +} + +VkTools::ManagedBuffer VkTools::createGPUBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkDevice logicalDevice, VkPhysicalDevice physicalDevice, bool hostVisible) { + // Prepare for creation of a buffer + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usage; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + ManagedBuffer buffer {}; + + VmaAllocationCreateInfo vmaInfo = {}; + vmaInfo.usage = hostVisible ? VMA_MEMORY_USAGE_CPU_ONLY : VMA_MEMORY_USAGE_GPU_ONLY; + vmaInfo.requiredFlags = properties; + + // Create the buffer. + if (VkResult status = vmaCreateBuffer(allocator, &bufferInfo, &vmaInfo, &buffer.buffer, &buffer.allocation, nullptr); status != VK_SUCCESS) + throw std::runtime_error("Unable to create GPU buffer: " + std::to_string(status)); + + return buffer; +} + +uint32_t findMemoryIndex(uint32_t type, VkMemoryPropertyFlags properties, VkPhysicalDevice physicalDevice) { + // Get the physical properties of the device. + VkPhysicalDeviceMemoryProperties physProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &physProperties); + + // Iterate the device and search for a suitable index + for (uint32_t i = 0; i < physProperties.memoryTypeCount; i++) + // If the type matches, and the properties are what we desire, then ship it. + if ((type & (1 << i)) && ((physProperties.memoryTypes[i].propertyFlags & properties) == properties)) + return i; + + throw std::runtime_error("Unable to find a suitable memory type on the physical device."); +} + +void VkTools::immediateExecute(const std::function& execute, VulkanDevice* dev) { + vlkx::ImmediateCommand cmd({ dev->graphicsQueue, dev->queueData.graphics }); + cmd.run(execute); +} + +void VkTools::copyGPUBuffer(VkBuffer source, VkBuffer dest, VkDeviceSize length, VulkanDevice* dev) { + immediateExecute([&](const VkCommandBuffer& commands) { + // Prepare to copy the data between buffers + VkBufferCopy copyInfo = {}; + copyInfo.srcOffset = 0; + copyInfo.dstOffset = 0; + copyInfo.size = length; + + // Copy the data. + vkCmdCopyBuffer(commands, source, dest, 1, ©Info); + }, dev); +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/ValidationAndExtension.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/ValidationAndExtension.cpp index 1ae8e66..4b8de03 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/ValidationAndExtension.cpp +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/ValidationAndExtension.cpp @@ -41,6 +41,10 @@ std::vector ValidationAndExtension::getRequiredExtensions(SDL_Windo SDL_Vulkan_GetInstanceExtensions(window, &count, nullptr); std::vector extensions = { + #ifdef __APPLE__ + "VK_KHR_portability_enumeration", + #endif + "VK_KHR_get_physical_device_properties2" }; size_t additional_extension_count = extensions.size(); @@ -57,17 +61,16 @@ std::vector ValidationAndExtension::getRequiredExtensions(SDL_Windo } static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData - ) { + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objExt, + uint64_t obj, + size_t location, + int32_t code, + const char* layer, + const char* message, + void* user) { - std::cerr << "Validation from layer " << pLayerPrefix << ": " << pMessage << std::endl; + std::cerr << "Validation from layer " << layer << ": " << message << std::endl; return false; } diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanDevice.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanDevice.cpp index 5a71eb9..8162d65 100644 --- a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanDevice.cpp +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanDevice.cpp @@ -26,6 +26,7 @@ void VulkanDevice::choosePhysicalDevice(VkInstance* vulkan, VkSurfaceKHR surface for (const auto& device : physicals) { VkPhysicalDeviceProperties props; vkGetPhysicalDeviceProperties(device, &props); + limits = props.limits; bool dedicated = props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; spdlog::debug(std::string("Device: ") + props.deviceName + ", discrete: " + (dedicated ? "yes" : "no")); @@ -62,7 +63,7 @@ bool VulkanDevice::isSuitable(VkPhysicalDevice device, VkSurfaceKHR surface) { QueueFamilies VulkanDevice::checkQueues(VkPhysicalDevice device, VkSurfaceKHR surface) { QueueFamilies families; - // Enumerate queueues + // Enumerate queues uint32_t queueCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(device, &queueCount, nullptr); diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanManager.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanManager.cpp deleted file mode 100644 index 95bc24a..0000000 --- a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanManager.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#define VMA_IMPLEMENTATION - -#include - -#define VKTOOLS_IMPLEMENTATION - -#include - -#include -#include "spdlog/spdlog.h" -#include "spdlog/sinks/stdout_color_sinks.h" - -VulkanManager::VulkanManager() { rayTraceMode = false; } - -VulkanManager::~VulkanManager() = default; - -VulkanManager* VulkanManager::instance = nullptr; - - -VmaAllocator VkTools::g_allocator; -VkInstance VkTools::g_Instance = VK_NULL_HANDLE; -VkPhysicalDevice VkTools::g_PhysicalDevice = VK_NULL_HANDLE; -VkDevice VkTools::g_Device = VK_NULL_HANDLE; -uint32_t VkTools::g_QueueFamily = (uint32_t)-1; -VkQueue VkTools::g_Queue = VK_NULL_HANDLE; -VkDebugReportCallbackEXT VkTools::g_DebugReport = VK_NULL_HANDLE; - -VulkanManager* VulkanManager::getInstance() { - return VulkanManager::instance != nullptr ? VulkanManager::instance - : (VulkanManager::instance = new VulkanManager()); -} - -void VulkanManager::createAppAndVulkanInstance(bool enableValidation, ValidationAndExtension* validations) { - VkApplicationInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - info.pApplicationName = "Sup"; - info.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); - info.pEngineName = "Infinity Drive"; - info.engineVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); - info.apiVersion = VK_API_VERSION_1_0; - - VkInstanceCreateInfo instanceInfo = {}; - instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instanceInfo.pApplicationInfo = &info; - - auto extensions = validations->getRequiredExtensions(wnd, true); - instanceInfo.enabledExtensionCount = static_cast(extensions.size()); - instanceInfo.ppEnabledExtensionNames = &extensions[0]; - - auto layers = validations->requiredValidations; - if (enableValidation) { - instanceInfo.enabledLayerCount = static_cast(layers.size()); - instanceInfo.ppEnabledLayerNames = &layers[0]; - } else { - instanceInfo.enabledLayerCount = 0; - } - - auto status = vkCreateInstance(&instanceInfo, nullptr, &vulkan); - if (status != VK_SUCCESS) { - throw std::runtime_error("Failed to initialize Vulkan: " + std::to_string(status)); - } - -} - -void VulkanManager::initVulkan(SDL_Window* window) { - wnd = window; - validators = new ValidationAndExtension(); - - spdlog::info("Initializing Infinity Drive rendering engine"); - spdlog::default_logger()->set_level(spdlog::level::debug); - - if (!validators->checkValidationSupport()) - throw std::runtime_error("Validation not available"); - - createAppAndVulkanInstance(validationRequired, validators); - - validators->setupDebugCallback(validationRequired, vulkan); - - if (SDL_Vulkan_CreateSurface(window, vulkan, &surface) != SDL_TRUE) - throw std::runtime_error("Unable to create Vulkan Surface"); - - this->device = new VulkanDevice(); - this->device->choosePhysicalDevice(&vulkan, surface); - this->device->createLogicalDevice(surface, validationRequired, validators); - - VmaAllocatorCreateInfo allocatorInfo = {}; - allocatorInfo.physicalDevice = this->device->physical; - allocatorInfo.device = this->device->logical; - allocatorInfo.instance = this->vulkan; - vmaCreateAllocator(&allocatorInfo, &this->allocator); - VkTools::g_allocator = this->allocator; - VkTools::g_PhysicalDevice = this->device->physical; - VkTools::g_Device = this->device->logical; - VkTools::g_Instance = this->vulkan; - - this->swapchain = new SwapChain(); - this->swapchain->create(surface); - - this->renderPass = new RenderPass(); - - // Set up for vertex rendering - this->renderPass->createVertexRenderPass(swapchain->format); - this->renderTexture = new SingleRenderTexture(); - - this->renderTexture->createViewsAndFramebuffer(swapchain->images, swapchain->format, - swapchain->extent,renderPass->pass - ); - - this->buffers = new CommandBuffer(); - this->buffers->createCommandPoolAndBuffers(swapchain->images.size()); - - // Create semaphores for render events - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - vkCreateSemaphore(device->logical, &semaphoreInfo, nullptr, &newImageSem); - vkCreateSemaphore(device->logical, &semaphoreInfo, nullptr, &renderDoneSem); - - // Create fences for the frames - inFlight.resize(MAX_FRAMES); - VkFenceCreateInfo fenceInfo = {}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - for (size_t i = 0; i < MAX_FRAMES; i++) { - if (vkCreateFence(device->logical, &fenceInfo, nullptr, &inFlight[i]) != VK_SUCCESS) - throw std::runtime_error("Unable to create fence for a frame"); - } - - spdlog::info("Infinity Drive initialization finished."); -} - -void VulkanManager::startDraw() { - // Prepare for a new frame to start - vkAcquireNextImageKHR(device->logical, swapchain->swapChain, - std::numeric_limits::max(), newImageSem,VK_NULL_HANDLE, &imageIndex - ); - - vkWaitForFences(device->logical, 1, &inFlight[imageIndex], VK_TRUE, - std::numeric_limits::max() - ); - - vkResetFences(device->logical, 1, &inFlight[imageIndex]); - - // Fetch the next command buffer - currentCommandBuffer = buffers->buffers[imageIndex]; - buffers->beginCommandBuffer(currentCommandBuffer); - - // Setup render pass; setup clear color - VkClearValue clearColor = { 1.0f, 0.0f, 0.0f, 1.0f }; // Red - - // Execute render pass - renderPass->beginRenderPass({ clearColor }, currentCommandBuffer, dynamic_cast(renderTexture)->swapChainFramebuffers[imageIndex], dynamic_cast(renderTexture)->swapChainImageExtent); -} - -void VulkanManager::endDraw() { - // End command buffer first - renderPass->endRenderPass(currentCommandBuffer); - buffers->endCommandBuffer(currentCommandBuffer); - - // Prepare to submit all draw commands to the GPU - VkPipelineStageFlags waitStages[] = { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT - }; - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = ¤tCommandBuffer; - submitInfo.pWaitDstStageMask = waitStages; - // Wait for the New Image semaphore, and signal the Render Done semaphore when finished - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = &newImageSem; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &renderDoneSem; - - // Submit. - vkQueueSubmit(VulkanManager::getInstance()->getDevice()->graphicsQueue, 1, &submitInfo, inFlight[imageIndex]); - - // Prepare to show the drawn frame on the screen. - VkPresentInfoKHR presentInfo = {}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &swapchain->swapChain; - presentInfo.pImageIndices = &imageIndex; - // Wait until render is finished before presenting. - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &renderDoneSem; - - // Show. - vkQueuePresentKHR(VulkanManager::getInstance()->getDevice()->presentationQueue, &presentInfo); - - // Wait for the GPU to catch up - vkQueueWaitIdle(VulkanManager::getInstance()->getDevice()->presentationQueue); -} - -void VulkanManager::cleanup() { - // Wait for the GPU to not be busy - vkDeviceWaitIdle(VulkanManager::getInstance()->getDevice()->logical); - - // Destroy our own data - vkDestroySemaphore(device->logical, renderDoneSem, nullptr); - vkDestroySemaphore(device->logical, newImageSem, nullptr); - - for (size_t i = 0; i < MAX_FRAMES; i++) { - vkDestroyFence(device->logical, inFlight[i], nullptr); - } - - buffers->destroy(); - renderTexture->destroy(); - renderPass->destroy(); - swapchain->destroy(); - - // Destroy the Vulkan Device - VulkanManager::getInstance()->getDevice()->destroy(); - - // Delete the layer validators. - validators->destroy(validationRequired, vulkan); - - // Delete the surface and Vulkan instance. - vkDestroySurfaceKHR(vulkan, surface, nullptr); - vkDestroyInstance(vulkan, nullptr); - - vmaDestroyAllocator(allocator); - - // Delete allocated memory for our own data. - delete buffers; - delete renderTexture; - delete renderPass; - delete swapchain; - delete device; - delete validators; -} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanModule.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanModule.cpp new file mode 100644 index 0000000..8f432ed --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/VulkanModule.cpp @@ -0,0 +1,348 @@ +#define VMA_IMPLEMENTATION + +#include +#include + +#include +#include "spdlog/spdlog.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include "core/ShadowApplication.h" +#include "core/SDL2Module.h" +#include "vlkx/render/render_pass/ScreenRenderPass.h" +#include + +#define CATCH(x) \ + try { x } catch (std::exception& e) { spdlog::error(e.what()); exit(0); } + +SHObject_Base_Impl(VulkanModule) + +std::unique_ptr renderPass; +bool renderingGeometry; +std::unique_ptr editorPass; + +std::unique_ptr editorRenderCommands; + +const std::unique_ptr& VulkanModule::getRenderPass() { + return renderPass; +} + +VulkanModule::VulkanModule() { instance = this; } + +VulkanModule::~VulkanModule() = default; + +VulkanModule* VulkanModule::instance = nullptr; + +VulkanModule* VulkanModule::getInstance() { + return VulkanModule::instance != nullptr ? VulkanModule::instance + : (VulkanModule::instance = new VulkanModule()); +} + +void VulkanModule::EnableEditor() { + editorEnabled = true; +} + +VkExtent2D VulkanModule::GetRenderExtent() { + if (editorEnabled) { + if (renderingGeometry) + return editorContentFrames[0]->getExtent(); + else + return swapchain->extent; + } else + return swapchain->extent; +} + +void VulkanModule::Recreate() { + vkDeviceWaitIdle(device->logical); + + device->swapChain = device->checkSwapchain(device->physical, surface); + + if (device->swapChain.capabilities.currentExtent.width == 0 && device->swapChain.capabilities.currentExtent.height == 0) { + []() { + SDL_Event event; + while (true) { + while (SDL_PollEvent(&event)) { + if (event.type == SDL_WINDOWEVENT && (event.window.event == SDL_WINDOWEVENT_MAXIMIZED || event.window.event == SDL_WINDOWEVENT_SHOWN || event.window.event == SDL_WINDOWEVENT_RESIZED || event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED || event.window.event == SDL_WINDOWEVENT_RESTORED)) + return; + } + } + }(); + } + + device->swapChain = device->checkSwapchain(device->physical, surface); + + swapchain->destroy(); + swapchain->create(surface); + + renderPass->initializeRenderPass(); + editorPass->initializeRenderPass(); +} + +void VulkanModule::PreInit() { + spdlog::info("Vulkan Renderer Module loading.."); + + + auto shApp = ShadowEngine::ShadowApplication::Get(); + + ShadowEngine::ModuleManager &moduleManager = shApp.GetModuleManager(); + + auto sdl2module = moduleManager.GetModuleByType(); + + CATCH(initVulkan(sdl2module->_window->sdlWindowPtr);) + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + VkDescriptorPool imGuiPool; + VkDescriptorPoolSize pool_sizes[] = + { + { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, + { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } + }; + + VkDescriptorPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes); + pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); + pool_info.pPoolSizes = pool_sizes; + vkCreateDescriptorPool(getDevice()->logical, &pool_info, VK_NULL_HANDLE, &imGuiPool); + + // Setup Platform/Renderer backends + ImGui_ImplSDL2_InitForVulkan(wnd); + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.Instance = getVulkan(); + init_info.PhysicalDevice = getDevice()->physical; + init_info.Device = getDevice()->logical; + init_info.QueueFamily = getDevice()->queueData.graphics; + init_info.Queue = getDevice()->graphicsQueue; + init_info.PipelineCache = VK_NULL_HANDLE; + init_info.DescriptorPool = imGuiPool; + init_info.Subpass = 1; + init_info.MinImageCount = getSwapchain()->images.size(); + init_info.ImageCount = getSwapchain()->images.size(); + init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + init_info.Allocator = VK_NULL_HANDLE; + init_info.CheckVkResultFn = nullptr; + + + if (editorEnabled) { + editorContentFrames.resize(1); + for (size_t i = 0; i < 1; i++) { + vlkx::TextureImage::Meta meta { + {nullptr}, {vlkx::ImageUsage::renderTarget(0)}, VK_FORMAT_R8G8B8A8_SRGB, 640, 480, 4 + }; + editorContentFrames[i] = std::make_unique(0, vlkx::ImageSampler::Config {}, meta); + } + + editorRenderCommands = std::make_unique(editorContentFrames.size()); + } + + renderPass = std::make_unique(vlkx::RendererConfig { editorEnabled ? 1 : 2, editorEnabled ? editorContentFrames : swapchain->images, !editorEnabled } ); + renderPass->initializeRenderPass(); + editorPass = std::make_unique(vlkx::RendererConfig { 2, swapchain->images, true } ); + editorPass->initializeRenderPass(); + + ImGui_ImplVulkan_Init(&init_info, **(editorEnabled ? editorPass : renderPass)->getPass()); + + VkTools::immediateExecute([](const VkCommandBuffer& commands) { ImGui_ImplVulkan_CreateFontsTexture(commands); }, getDevice()); + + if (editorEnabled) { + editorRenderPlanes.resize(editorContentFrames.size()); + for (size_t i = 0; i < editorContentFrames.size(); i++) { + editorRenderPlanes[i] = ImGui_ImplVulkan_AddTexture(VkTools::createSampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 0, device->logical), editorContentFrames[i]->getView(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + } + + renderingGeometry = false; +} + +void VulkanModule::Init() { +} + +void VulkanModule::BeginRenderPass(const std::unique_ptr& commands) { + const auto update = !editorEnabled ? [](const int frame) { ShadowEngine::ModuleManager::instance->Update(frame); } : nullptr; + + const auto res = commands->execute(commands->getFrame(), swapchain->swapChain, update, + [this](const VkCommandBuffer& buffer, int frame) { + (editorEnabled ? editorPass : renderPass)->getPass()->execute(buffer, frame, { + // Render our model + [&](const VkCommandBuffer &commands) { + if (!editorEnabled) { + renderingGeometry = true; + ShadowEngine::ModuleManager::instance->Render(const_cast(commands), frame); + ShadowEngine::ModuleManager::instance->LateRender(const_cast(commands), frame); + renderingGeometry = false; + } + }, + // Render ImGUI + [&](const VkCommandBuffer &commands) { + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); + + if (editorEnabled) + ImGui::Image(editorRenderPlanes[0], { 640, 480 }); + + ShadowEngine::ModuleManager::instance->OverlayRender(); + + ImGui::Render(); + ImGuiIO &io = ImGui::GetIO(); + (void) io; + + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commands); + + // Update and Render additional Platform Windows + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + } + } + }); + } + ); + + if (res.has_value()) + ShadowEngine::ModuleManager::getInstance()->Recreate(); +} + +void VulkanModule::PreRender() { + if (editorEnabled) { + editorRenderCommands->executeSimple(editorRenderCommands->getFrame(), [](const int frame) { ShadowEngine::ModuleManager::instance->Update(frame); }, + [&](const VkCommandBuffer& buffer, int frame) { + renderPass->getPass()->execute(buffer, frame, { + [&](const VkCommandBuffer& commands) { + renderingGeometry = true; + ShadowEngine::ModuleManager::instance->Render(const_cast(commands), frame); + ShadowEngine::ModuleManager::instance->LateRender(const_cast(commands), frame); + renderingGeometry = false; + } + }); + } + ); + + } +} + + +void VulkanModule::OverlayRender() {} +void VulkanModule::AfterFrameEnd() {} +void VulkanModule::Render(VkCommandBuffer& commands, int frame) {} +void VulkanModule::Update(int frame) {} +void VulkanModule::Event(SDL_Event *e) { (void)e; } + +void VulkanModule::LateRender(VkCommandBuffer& commands, int frame) { +} + +void VulkanModule::Destroy() { + ImGui_ImplVulkan_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); +} + +void VulkanModule::createAppAndVulkanInstance(bool enableValidation, ValidationAndExtension* validations) { + VkApplicationInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + info.pApplicationName = "Sup"; + info.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); + info.pEngineName = "Infinity Drive"; + info.engineVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); + info.apiVersion = VK_API_VERSION_1_0; + + VkInstanceCreateInfo instanceInfo = {}; + instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; +#ifdef __APPLE__ + VkFlags instanceFlag = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; +#else + VkFlags instanceFlag = 0; +#endif + instanceInfo.flags = instanceFlag; + instanceInfo.pApplicationInfo = &info; + + auto extensions = validations->getRequiredExtensions(wnd, true); + instanceInfo.enabledExtensionCount = static_cast(extensions.size()); + instanceInfo.ppEnabledExtensionNames = &extensions[0]; + + auto layers = validations->requiredValidations; + if (enableValidation) { + instanceInfo.enabledLayerCount = static_cast(layers.size()); + instanceInfo.ppEnabledLayerNames = &layers[0]; + } else { + instanceInfo.enabledLayerCount = 0; + } + + auto status = vkCreateInstance(&instanceInfo, nullptr, &vulkan); + if (status != VK_SUCCESS) { + throw std::runtime_error("Failed to initialize Vulkan: " + std::to_string(status)); + } + +} + +void VulkanModule::initVulkan(SDL_Window* window) { + wnd = window; + validators = new ValidationAndExtension(); + + spdlog::info("Initializing Infinity Drive rendering engine"); + spdlog::default_logger()->set_level(spdlog::level::debug); + + if (!validators->checkValidationSupport()) + throw std::runtime_error("Validation not available"); + + createAppAndVulkanInstance(validationRequired, validators); + + validators->setupDebugCallback(validationRequired, vulkan); + + if (SDL_Vulkan_CreateSurface(window, vulkan, &surface) != SDL_TRUE) + throw std::runtime_error("Unable to create Vulkan Surface"); + + this->device = new VulkanDevice(); + this->device->choosePhysicalDevice(&vulkan, surface); + this->device->createLogicalDevice(surface, validationRequired, validators); + + VmaAllocatorCreateInfo allocatorInfo = {}; + allocatorInfo.physicalDevice = this->device->physical; + allocatorInfo.device = this->device->logical; + allocatorInfo.instance = this->vulkan; + vmaCreateAllocator(&allocatorInfo, &this->allocator); + VkTools::allocator = allocator; + + this->swapchain = new SwapChain(); + this->swapchain->create(surface); + spdlog::info("Infinity Drive initialization finished."); +} + +void VulkanModule::cleanup() { + // Wait for the GPU to not be busy + vkDeviceWaitIdle(VulkanModule::getInstance()->getDevice()->logical); + + swapchain->destroy(); + + // Destroy the Vulkan Device + VulkanModule::getInstance()->getDevice()->destroy(); + + // Delete the layer validators. + validators->destroy(validationRequired, vulkan); + + // Delete the surface and Vulkan instance. + vkDestroySurfaceKHR(vulkan, surface, nullptr); + vkDestroyInstance(vulkan, nullptr); + + vmaDestroyAllocator(allocator); + + delete swapchain; + delete device; + delete validators; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Buffer.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Buffer.cpp new file mode 100644 index 0000000..821ec1b --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Buffer.cpp @@ -0,0 +1,239 @@ +#include "vlkx/vulkan/abstraction/Buffer.h" +#include "vlkx/vulkan/Tools.h" +#include "vlkx/vulkan/VulkanModule.h" +#include + +namespace vlkx { + + void executeBulkCopy(VkTools::ManagedBuffer buffer, const std::vector& meta) { + void* dst; + vmaMapMemory(VulkanModule::getInstance()->getAllocator(), buffer.allocation, &dst); + // GPU memory accessible through dst pointer + + for (const auto& info : meta) { + memcpy(static_cast(dst) + info.start, info.data, info.length); + } + + // Unmap GPU memory + vmaUnmapMemory(VulkanModule::getInstance()->getAllocator(), buffer.allocation); + } + + StagingBuffer::StagingBuffer(const vlkx::Buffer::BulkCopyMeta ©Meta) : dataSize(copyMeta.length) { + setBuffer(VkTools::createGPUBuffer(dataSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VulkanModule::getInstance()->getDevice()->logical, VulkanModule::getInstance()->getDevice()->physical)); + + executeBulkCopy(get(), copyMeta.metas); + } + + void StagingBuffer::copy(const VkBuffer &target) const { + VkTools::copyGPUBuffer(get().buffer, target, dataSize, VulkanModule::getInstance()->getDevice()); + } + + std::vector VertexBuffer::getAttrs(uint32_t start) const { + std::vector descs; + descs.reserve(attributes.size()); + + for (const auto& attr : attributes) { + descs.push_back(VkVertexInputAttributeDescription { + start++, 0, attr.format, attr.offset + }); + } + + return descs; + } + + void VertexBuffer::draw(const VkCommandBuffer &commands, uint32_t verts, uint32_t instances) { + vkCmdDraw(commands, verts, instances, 0, 0); + } + + void VertexBuffer::create(VkDeviceSize totalSize, bool dynamic, bool indexes) { + VkBufferUsageFlags usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + VkMemoryPropertyFlags props; + + if (dynamic) { + props = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + } else { + usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + props = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + + if (indexes) + usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + + setBuffer(VkTools::createGPUBuffer(totalSize, usage, props, VulkanModule::getInstance()->getDevice()->logical, VulkanModule::getInstance()->getDevice()->physical, dynamic)); + } + + DynamicBuffer::DynamicBuffer(size_t size, bool hasIndices, vlkx::VertexBuffer *buffer) : hasIndices(hasIndices), vertexBuffer(buffer) { + resize(size); + } + + void DynamicBuffer::resize(size_t pSize) { + if (pSize <= bufferSize()) return; + + if (pSize > 0) { + // todo: release the buffer & device memory + } + + size = pSize; + vertexBuffer->create(size, true, hasIndices); + } + + Buffer::BulkCopyMeta PerVertexBuffer::NoIndexBufferMeta::prepareCopy(vlkx::PerVertexBuffer *buffer) const { + auto& meshInfos = buffer->meshDataInfo.emplace().info; + meshInfos.reserve(perMeshVertices.size()); + + std::vector copyMetas; + copyMetas.reserve(perMeshVertices.size()); + + VkDeviceSize offset = 0; + for (const auto& verts : perMeshVertices) { + meshInfos.push_back(MeshDataNoIndex::Info { static_cast(verts.unitsPerMesh), offset }); + copyMetas.push_back(Buffer::CopyMeta { verts.data, verts.sizePerMesh, offset }); + offset += verts.sizePerMesh; + } + + return Buffer::BulkCopyMeta { offset, std::move(copyMetas) }; + } + + Buffer::BulkCopyMeta PerVertexBuffer::SharedIndexMeta::prepareCopy(vlkx::PerVertexBuffer *buffer) const { + auto& meshInfos = buffer->meshDataInfo.emplace().info; + meshInfos.reserve(meshes); + + VkDeviceSize offset = sharedIndices.sizePerMesh; + for (int i = 0; i < meshes; ++i) { + meshInfos.push_back(MeshDataIndex::Info { static_cast(sharedIndices.unitsPerMesh), 0, offset }); + offset += perMeshVertex.sizePerMesh; + } + + return Buffer::BulkCopyMeta { offset, { { sharedIndices.data, sharedIndices.sizePerMesh, 0 }, { perMeshVertex.data, perMeshVertex.sizePerMesh * meshes, sharedIndices.sizePerMesh } } }; + } + + + Buffer::BulkCopyMeta PerVertexBuffer::NoShareMeta::prepareCopy(vlkx::PerVertexBuffer *buffer) const { + auto& meshInfos = buffer->meshDataInfo.emplace().info; + meshInfos.reserve(perMeshMeta.size()); + + std::vector copyMetas; + copyMetas.reserve(perMeshMeta.size() * 2); + + VkDeviceSize offset = 0; + for (const auto& meta : perMeshMeta) { + const size_t indicesSize = meta.indices.sizePerMesh; + const size_t verticesSize = meta.vertices.sizePerMesh; + const VkDeviceSize verticesOffset = offset + indicesSize; + + meshInfos.push_back(MeshDataIndex::Info { static_cast(meta.indices.unitsPerMesh), offset, verticesOffset }); + copyMetas.push_back(Buffer::CopyMeta { meta.indices.data, indicesSize, offset }); + copyMetas.push_back(Buffer::CopyMeta { meta.vertices.data, verticesSize, verticesOffset }); + + offset += indicesSize + verticesSize; + } + + return Buffer::BulkCopyMeta { offset, std::move(copyMetas) }; + } + + void PerVertexBuffer::draw(const VkCommandBuffer &commands, uint32_t bind, int index, uint32_t instances) const { + if (const auto* meshNoIndex = std::get_if(&meshDataInfo); meshNoIndex != nullptr) { + const auto& meshInfo = meshNoIndex->info[index]; + vkCmdBindVertexBuffers(commands, bind, 1, &getBuffer(), &meshInfo.vertexStart); + vkCmdDraw(commands, meshInfo.vertexCount, instances, 0, 0); + } else if (const auto* meshIndex = std::get_if(&meshDataInfo); meshIndex != nullptr) { + const auto& meshInfo = meshIndex->info[index]; + vkCmdBindIndexBuffer(commands, getBuffer(), meshInfo.indexStart, VK_INDEX_TYPE_UINT32); + vkCmdBindVertexBuffers(commands, bind, 1, &getBuffer(), &meshInfo.vertexStart); + vkCmdDrawIndexed(commands, meshInfo.indexCount, instances, 0, 0, 0); + } + } + + StaticPerVertexBuffer::StaticPerVertexBuffer(const vlkx::PerVertexBuffer::BufferDataMeta &info, + std::vector &&attrs) : PerVertexBuffer(std::move(attrs)) { + const BulkCopyMeta copy = info.prepareCopy(this); + create(copy.length, false, info.hasIndices()); + const StagingBuffer staging(copy); + staging.copy(getBuffer()); + } + + void DynamicPerVertexBuffer::copyToDevice(const vlkx::PerVertexBuffer::BufferDataMeta &meta) { + const BulkCopyMeta copy = meta.prepareCopy(this); + resize(copy.length); + executeBulkCopy(get(), copy.metas); + } + + void PerInstanceVertexBuffer::bind(const VkCommandBuffer &commands, uint32_t bindPoint, int offset) const { + const VkDeviceSize size = sizePerInstance * offset; + vkCmdBindVertexBuffers(commands, bindPoint, 1, &getBuffer(), &size); + } + + StaticPerInstanceBuffer::StaticPerInstanceBuffer(uint32_t size, const void *data, uint32_t instances, + std::vector &&attrs) : PerInstanceVertexBuffer(size, std::move(attrs)) { + const uint32_t totalSize = size * instances; + create(totalSize, false, false); + + const BulkCopyMeta copy { totalSize, { {data, totalSize, 0} } }; + const StagingBuffer staging(copy); + staging.copy(getBuffer()); + } + + void DynamicPerInstanceBuffer::copyToDevice(const void *data, uint32_t instances) { + const uint32_t totalSize = getSize() * instances; + const BulkCopyMeta copy { totalSize, { { data, totalSize, 0 } } }; + resize(totalSize); + executeBulkCopy(get(), copy.metas); + } + + UniformBuffer::UniformBuffer(size_t chunkSize, int chunks) : DataBuffer(), chunkSize(chunkSize), numChunks(chunks) { + const VkDeviceSize alignment = VulkanModule::getInstance()->getDevice()->limits.minUniformBufferOffsetAlignment; + chunkLength = (chunkSize + alignment - 1) / alignment * alignment; + + data = new char[chunkSize * numChunks]; + setBuffer(VkTools::createGPUBuffer(chunkLength * numChunks, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VulkanModule::getInstance()->getDevice()->logical, VulkanModule::getInstance()->getDevice()->physical, true)); + } + + void UniformBuffer::upload(int index) const { + checkIndex(index); + const VkDeviceSize srcOffset = chunkSize * index; + const VkDeviceSize dstOffset = chunkLength * index; + + // TODO: dstoffset? + executeBulkCopy(get(), { { data + srcOffset, chunkSize, 0 } } ); + } + + void UniformBuffer::upload(int index, VkDeviceSize dataSize, VkDeviceSize start) const { + checkIndex(index); + const VkDeviceSize srcOffset = chunkSize * index + start; + const VkDeviceSize dstOffset = chunkLength * index + start; + + // TODO: dstoffset? + executeBulkCopy(get(), { { data + srcOffset, dataSize, 0 } } ); + } + + VkDescriptorBufferInfo UniformBuffer::getDescriptorInfo(int index) const { + checkIndex(index); + return VkDescriptorBufferInfo { getBuffer(), chunkLength * index, chunkSize}; + } + + void UniformBuffer::checkIndex(int index) const { + if (index > numChunks) + throw std::runtime_error("Attempting to access uniform chunk " + std::to_string(index) + " out of range."); + + } + + PushConstant::PushConstant(size_t size, int numFrames) : sizePerFrame(static_cast(size)), numFrames(numFrames) { + if (size > 128) + throw std::runtime_error("Attempting to push constant of size " + std::to_string(size) + ", max ix 128."); + + data = new char[size * numFrames]; + } + + void PushConstant::upload(const VkCommandBuffer &commands, const VkPipelineLayout &pipelineLayout, int frame, + uint32_t offset, VkShaderStageFlags stage) const { + checkIndex(frame); + void* data = getData(frame); + vkCmdPushConstants(commands, pipelineLayout, stage, offset, sizePerFrame, data); + } + + void PushConstant::checkIndex(int index) const { + if (index > numFrames) + throw std::runtime_error("Attempting to access push constant for frame " + std::to_string(index) + " out of range."); + + } +} diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Commands.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Commands.cpp new file mode 100644 index 0000000..2c13eed --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Commands.cpp @@ -0,0 +1,177 @@ +#include "vlkx/vulkan/abstraction/Commands.h" +#include "vlkx/vulkan/VulkanModule.h" + +#include + +vlkx::CommandBuffer::CommandBuffer() { + dev = VulkanModule::getInstance()->getDevice(); +} + +VkCommandPool createPool(vlkx::Queue queue, bool shortLived) { + VkCommandPool pool; + VkCommandPoolCreateInfo poolCreateInfo = {}; + poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolCreateInfo.queueFamilyIndex = queue.queueIndex; + poolCreateInfo.flags = shortLived ? VK_COMMAND_POOL_CREATE_TRANSIENT_BIT : VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + // Create the pool + if (vkCreateCommandPool(VulkanModule::getInstance()->getDevice()->logical, &poolCreateInfo, nullptr, &pool) != VK_SUCCESS) + throw std::runtime_error("Unable to allocate a temporary command pool"); + + return pool; +} + +std::vector allocateBuffers(const VkCommandPool& pool, uint32_t amount) { + const VkCommandBufferAllocateInfo allocate { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + nullptr, pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, amount + }; + + std::vector buffers(amount); + if (vkAllocateCommandBuffers(VulkanModule::getInstance()->getDevice()->logical, &allocate, buffers.data()) != VK_SUCCESS) + throw std::runtime_error("Unable to allocate command buffers"); + + return buffers; +} + +void recordCommands(const VkCommandBuffer& commands, VkCommandBufferUsageFlags flags, const vlkx::CommandBuffer::Command& record) { + const VkCommandBufferBeginInfo begin { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, flags, nullptr + }; + + if (vkBeginCommandBuffer(commands, &begin) != VK_SUCCESS) + throw std::runtime_error("Unable to begin listening on command buffer"); + if (record != nullptr) + record(commands); + if (vkEndCommandBuffer(commands) != VK_SUCCESS) + throw std::runtime_error("Unable to end listening on command buffer"); +} + +std::optional parseResult(VkResult result) { + switch(result) { + case VK_ERROR_OUT_OF_DATE_KHR: return result; + case VK_SUCCESS: + case VK_SUBOPTIMAL_KHR: + return std::nullopt; + + default: + throw std::runtime_error("Command buffer returned unknown result " + std::to_string(result)); + } +} + +vlkx::ImmediateCommand::ImmediateCommand(Queue queue) : queue(queue) { + const auto pool = createPool(queue, true); + setPool(pool); + commands = allocateBuffers(pool, 1)[0]; +} + +void vlkx::ImmediateCommand::run(const vlkx::CommandBuffer::Command &cmd) { + recordCommands(commands, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, cmd); + const VkSubmitInfo submit { + VK_STRUCTURE_TYPE_SUBMIT_INFO, + nullptr, 0, nullptr, nullptr, 1, + &commands, 0, nullptr + }; + + vkQueueSubmit(queue.queue, 1, &submit, VK_NULL_HANDLE); + vkQueueWaitIdle(queue.queue); +} + +vlkx::RenderCommand::RenderCommand(int frames) { + VulkanDevice* dev = VulkanModule::getInstance()->getDevice(); + + // Create semaphores for render events + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + vkCreateSemaphore(dev->logical, &semaphoreInfo, nullptr, &newImageSem); + vkCreateSemaphore(dev->logical, &semaphoreInfo, nullptr, &renderDoneSem); + + // Create fences for the frames + inFlight.resize(frames); + VkFenceCreateInfo fenceInfo = {}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for (size_t i = 0; i < frames; i++) { + if (vkCreateFence(dev->logical, &fenceInfo, nullptr, &inFlight[i]) != VK_SUCCESS) + throw std::runtime_error("Unable to create fence for a frame"); + } + + const auto pool = createPool({ dev->graphicsQueue, dev->queueData.graphics }, false); + setPool(pool); + commands = allocateBuffers(pool, static_cast(frames)); +} + +std::optional vlkx::RenderCommand::execute(int frame, const VkSwapchainKHR &swapchain, + const vlkx::RenderCommand::Update &update, + const vlkx::RenderCommand::Command &cmd) { + + const VkDevice& logical = VulkanModule::getInstance()->getDevice()->logical; + + vkWaitForFences(logical, 1, &inFlight[imageIndex], VK_TRUE, + std::numeric_limits::max() + ); + + if (update != nullptr) + update(frame); + + uint32_t nextFrame; + // Prepare for a new frame to start + const auto result = parseResult(vkAcquireNextImageKHR(logical, swapchain, + std::numeric_limits::max(), newImageSem, VK_NULL_HANDLE, &nextFrame + )); + + if (result.has_value()) + return result; + + recordCommands(commands[imageIndex], VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, [&cmd, nextFrame](const VkCommandBuffer& buffer) { + cmd(buffer, nextFrame); + }); + + constexpr VkPipelineStageFlags stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + const VkSubmitInfo submit { + VK_STRUCTURE_TYPE_SUBMIT_INFO, + nullptr, 1, &newImageSem, &stage, 1, &commands[imageIndex], 1, &renderDoneSem + }; + + vkResetFences(logical, 1, &inFlight[imageIndex]); + + if (VkResult res = vkQueueSubmit(VulkanModule::getInstance()->getDevice()->graphicsQueue, 1, &submit, inFlight[imageIndex]); res != VK_SUCCESS) + throw std::runtime_error("Failed to submit commands: " + std::to_string(res)); + + const VkPresentInfoKHR present { + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + nullptr, 1, &renderDoneSem, 1, &swapchain, &nextFrame, nullptr + }; + + return parseResult(vkQueuePresentKHR(VulkanModule::getInstance()->getDevice()->presentationQueue, &present)); +} + + +std::optional vlkx::RenderCommand::executeSimple(int frame, + const vlkx::RenderCommand::Update &update, + const vlkx::RenderCommand::Command &cmd) { + if (update != nullptr) + update(frame); + + const VkDevice& logical = VulkanModule::getInstance()->getDevice()->logical; + + vkWaitForFences(logical, 1, &inFlight[imageIndex], VK_TRUE, + std::numeric_limits::max() + ); + + recordCommands(commands[imageIndex], VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, [&cmd](const VkCommandBuffer& buffer) { + cmd(buffer, 0); + }); + + vkResetFences(logical, 1, &inFlight[imageIndex]); + + constexpr VkPipelineStageFlags stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + const VkSubmitInfo submit { + VK_STRUCTURE_TYPE_SUBMIT_INFO, + nullptr, 0, VK_NULL_HANDLE, &stage, 1, &commands[imageIndex], 0, VK_NULL_HANDLE + }; + + return std::make_optional(vkQueueSubmit(VulkanModule::getInstance()->getDevice()->graphicsQueue, 1, &submit, inFlight[imageIndex])); +} + diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Descriptor.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Descriptor.cpp new file mode 100644 index 0000000..452382a --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Descriptor.cpp @@ -0,0 +1,133 @@ +#include "vlkx/vulkan/abstraction/Descriptor.h" +#include +#include +#include + +using namespace vlkx; +// Returns 'pointer', assuming 'ExpectedType' and 'ActualType' are the same. +template +inline const ExpectedType* getPtr(const ActualType* pointer, std::true_type) { + return pointer; +} + +// Returns nullptr, assuming 'ExpectedType' and 'ActualType' are different. +template +inline const ExpectedType* getPtr(const ActualType* pointer, std::false_type) { + return nullptr; +} + +template +const ExpectedType* getPointer(const std::vector& container) { + return getPtr(container.data(), std::is_same()); +} + + +VkDescriptorPool createPool(std::vector metas) { + std::map sizes; + for (const auto& meta : metas) { + uint32_t length = 0; + for (const auto& binding : meta.bindings) + length += binding.length; + sizes[meta.type] += length; + } + + std::vector poolSizes; + for (const auto& pair : sizes) + poolSizes.push_back({ pair.first, pair.second }); + + const VkDescriptorPoolCreateInfo create { + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + nullptr, 0, + 1, static_cast(poolSizes.size()), poolSizes.data() + }; + + VkDescriptorPool pool; + if (vkCreateDescriptorPool(VulkanModule::getInstance()->getDevice()->logical, &create, nullptr, &pool) != VK_SUCCESS) + throw std::runtime_error("Unable to create Descriptor Pool"); + + return pool; +} + +VkDescriptorSetLayout createLayout(std::vector metas, bool dynamic) { + size_t bindings = 0; + for (const auto& meta : metas) + bindings += meta.bindings.size(); + + std::vector layoutBindings; + layoutBindings.reserve(bindings); + for (const auto& meta : metas) + for (const auto& binding : meta.bindings) + layoutBindings.push_back({ binding.bindPoint, meta.type, binding.length, meta.stage, nullptr }); + + const VkDescriptorSetLayoutCreateInfo create { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + nullptr, static_cast(dynamic ? VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR : 0), + static_cast(layoutBindings.size()), layoutBindings.data() + }; + + VkDescriptorSetLayout layout; + if (vkCreateDescriptorSetLayout(VulkanModule::getInstance()->getDevice()->logical, &create, nullptr, &layout) != VK_SUCCESS) + throw std::runtime_error("Unable to create Descriptor Set Layout"); + + return layout; +} + +VkDescriptorSet allocateSet(const VkDescriptorPool& pool, const VkDescriptorSetLayout& layout) { + const VkDescriptorSetAllocateInfo allocate { + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + nullptr, pool, 1, &layout + }; + + VkDescriptorSet set; + if (vkAllocateDescriptorSets(VulkanModule::getInstance()->getDevice()->logical, &allocate, &set) != VK_SUCCESS) + throw std::runtime_error("Unable to allocate descriptor set"); + + return set; +} + +template +std::vector createWrites(const VkDescriptorSet& set, VkDescriptorType type, const std::map>& map) { + + std::vector sets; + sets.reserve(map.size()); + + for (const auto& pair : map) { + const auto& info = pair.second; + sets.push_back(VkWriteDescriptorSet { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + nullptr, set, pair.first, 0, + static_cast(info.size()), type, + getPointer(info), + getPointer(info), + getPointer(info) + }); + } + + return sets; +} + +StaticDescriptor::StaticDescriptor(std::vector metas) : Descriptor() { + pool = createPool(metas); + const auto layout = createLayout(metas, false); + setLayout(layout); + set = allocateSet(pool, layout); +} + +const StaticDescriptor& StaticDescriptor::buffers(VkDescriptorType type, const BufferInfos &infos) const { + return updateSet(createWrites(set, type, infos)); +} + +const StaticDescriptor& StaticDescriptor::images(VkDescriptorType type, const ImageInfos &infos) const { + return updateSet(createWrites(set, type, infos)); +} + +const StaticDescriptor& StaticDescriptor::updateSet(const std::vector &write) const { + vkUpdateDescriptorSets(VulkanModule::getInstance()->getDevice()->logical, write.size(), write.data(), 0, nullptr); + return *this; +} + +void StaticDescriptor::bind(const VkCommandBuffer &commands, const VkPipelineLayout &layout, + VkPipelineBindPoint bindPoint) const { + vkCmdBindDescriptorSets(commands, bindPoint, layout, 0, 1, &set, 0, nullptr); +} + diff --git a/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Image.cpp b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Image.cpp new file mode 100644 index 0000000..eea62b4 --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-renderer/src/vulkan/abstraction/Image.cpp @@ -0,0 +1,439 @@ +#include "vlkx/vulkan/abstraction/Image.h" + +#include +#include +#include +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +#include "vlkx/vulkan/VulkanModule.h" +#include "shadow/util/File.h" + +namespace vlkx { + struct ImageConfig { + explicit ImageConfig(bool readable = false) { + if (readable) { + tiling = VK_IMAGE_TILING_LINEAR; + layout = VK_IMAGE_LAYOUT_PREINITIALIZED; + } else { + tiling = VK_IMAGE_TILING_OPTIMAL; + layout = VK_IMAGE_LAYOUT_UNDEFINED; + } + } + + uint32_t mipping = 1; + uint32_t layers = 1; + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; + VkImageTiling tiling; + VkImageLayout layout; + }; + + struct ImageData { + ImageDescriptor::Dimension dimensions; + const char* data; + }; + + ImageData loadImage(const std::string& path, int wantedChannels) { + shadowutil::FileData* data = shadowutil::loadFile(path); + int width, height, channels; + + stbi_uc* stbData = stbi_load_from_memory(reinterpret_cast(data->data.data()), data->size, &width, &height, &channels, wantedChannels); + if (stbData == nullptr) + throw std::runtime_error("Unable to read image file " + std::string(path)); + + switch (channels) { + case 1: + case 4: + break; + + case 3: { + stbi_image_free(stbData); + stbData = stbi_load_from_memory(reinterpret_cast(data->data.data()), data->size, &width, &height, &channels, STBI_rgb_alpha); + break; + } + + default: + throw std::runtime_error("Trying to load image with unsupported number of channels: " + std::to_string(channels)); + } + + return {{ static_cast(width), static_cast(height), static_cast(channels) },reinterpret_cast(stbData) }; + } + + std::optional findFormatWith(const std::vector& formats, VkFormatFeatureFlags feature) { + for (const auto format : formats) { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(VulkanModule::getInstance()->getDevice()->physical, format, &props); + if ((props.optimalTilingFeatures & feature) == feature) return format; + } + + return std::nullopt; + } + + VkFormat findFormatForChannels(int channels, const std::vector& usages, bool highPrecision = false) { + switch (channels) { + case 1: { + VkFormat best, alternative; + if (highPrecision) { + best = VK_FORMAT_R16_SFLOAT; + alternative = VK_FORMAT_R16G16B16A16_SFLOAT; + } else { + best = VK_FORMAT_R8_UNORM; + alternative = VK_FORMAT_R8G8B8A8_UNORM; + } + + if (findFormatWith({ best }, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT).has_value()) + return best; + else + return alternative; + } + + case 4: + if (highPrecision) + return VK_FORMAT_R16G16B16A16_SFLOAT; + else + return VK_FORMAT_R8G8B8A8_UNORM; + default: + throw std::runtime_error("Attempting to find format for invalid channels (RGB images have 4 channels!)"); + } + } + + VkFormat findFormatForDepthStencil() { + const auto format = findFormatWith({ VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); + if (!format.has_value()) + throw std::runtime_error("Unable to find a format for a depth stencil image."); + return format.value(); + } + + VkSampleCountFlagBits getMaxSamples(VkSampleCountFlags samples) { + for (const auto count : { VK_SAMPLE_COUNT_64_BIT, VK_SAMPLE_COUNT_32_BIT, VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_1_BIT }) { + if (samples & count) + return count; + } + + throw std::runtime_error("Multisampling isn't supported?"); + } + + Buffer::Buffer() { + } + + ImageDescriptor Image::loadCubeFromDisk(const std::string& directory, const std::array &files, + bool flipY) { + stbi_set_flip_vertically_on_load(flipY); + auto firstImage = loadImage(directory + "/" + files[0], STBI_default); + const ImageDescriptor::Dimension& dim = firstImage.dimensions; + char* data = new char[dim.getSize() * 6]; // TODO: Figure out how to make this delete + memcpy(data, firstImage.data, dim.getSize()); + for (size_t i = 1; i < 6; i++) { + auto image = loadImage(directory + "/" + files[1], STBI_default); + if (!(image.dimensions.width == dim.width && image.dimensions.height == dim.height && image.dimensions.channels == dim.channels)) + throw std::runtime_error("Image " + std::to_string(i) + "(" + directory + "/" + files[i] + ") has different dimensions from the first image."); + + memcpy(data + i * dim.getSize(), image.data, dim.getSize()); + } + + stbi_set_flip_vertically_on_load(false); + return { ImageDescriptor::Type::Cubemap, firstImage.dimensions, data }; + } + + ImageDescriptor Image::loadSingleFromDisk(std::string path, bool flipY) { + stbi_set_flip_vertically_on_load(flipY); + auto image = loadImage(std::move(path), STBI_default); + stbi_set_flip_vertically_on_load(false); + + return { ImageDescriptor::Type::Single, image.dimensions, image.data }; + } + + TextureImage::Meta createTextureMeta(const ImageDescriptor& image, const std::vector& usages) { + return TextureImage::Meta { + image.getData(), usages, + findFormatForChannels(image.getChannels(), usages), + image.getWidth(), image.getHeight(), image.getChannels(), + }; + } + + VkTools::ManagedImage createImage(const ImageConfig& config, VkImageCreateFlags flags, VkFormat format, const VkExtent3D& extent, VkImageUsageFlags usage) { + const auto device = VulkanModule::getInstance()->getDevice(); + + uint32_t graphicsQueue = (uint32_t) device->getQueues().graphics; + VkImageCreateInfo info { + VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr, + flags, VK_IMAGE_TYPE_2D, format, + extent, config.mipping, config.layers, config.samples, config.tiling, + usage, VK_SHARING_MODE_EXCLUSIVE, + 1, &graphicsQueue, config.layout + }; + + // Prepare the managed image + VkTools::ManagedImage image {}; + + // Set up image allocation + VmaAllocationCreateInfo allocateInfo = {}; + allocateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + + // Allocate + create the image + vmaCreateImage(VulkanModule::getInstance()->getAllocator(), &info, &allocateInfo, &image.image, &image.allocation, nullptr); + + return image; + } + + void waitForBarrier(const VkCommandBuffer& commands, const VkImageMemoryBarrier& barrier, const std::array& stages) { + vkCmdPipelineBarrier(commands, stages[0], stages[1], 0, 0, nullptr, 0, nullptr, 1, &barrier); + } + + void transitionImage(const VkImage& image, const ImageConfig& config, VkImageAspectFlags aspect, const std::array& layouts, const std::array& access, const std::array& stages) { + VkTools::immediateExecute([&](const VkCommandBuffer& commands) { + waitForBarrier(commands, + { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + nullptr, + access[0], access[1], + layouts[0], layouts[1], + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + image, + { aspect, 0, config.mipping, 0, config.layers } + }, stages); + }, VulkanModule::getInstance()->getDevice()); + } + + inline VkOffset3D convertExtent(const VkExtent2D& extent) { + return VkOffset3D { static_cast(extent.width), static_cast(extent.height), 1 }; + } + + inline VkExtent3D expandExtent(const VkExtent2D& extent) { + return VkExtent3D { extent.width, extent.height, 1 }; + } + + std::vector getExtentForMipmaps(const VkExtent3D& extent) { + const int largest = std::max(extent.width, extent.height); + const int mipping = std::floor(std::log2(largest)); + std::vector extents(mipping); + VkExtent2D imageExt { extent.width, extent.height }; + for (size_t level = 0; level < mipping; ++level) { + imageExt.width = imageExt.width > 1 ? imageExt.width / 2 : 1; + imageExt.height = imageExt.height > 1 ? imageExt.height / 2 : 1; + extents[level] = imageExt; + } + + return extents; + } + + void generateMipmaps(const VkImage& image, VkFormat format, const VkExtent3D& extent, const std::vector& mipExtents) { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(VulkanModule::getInstance()->getDevice()->physical, format, &props); + if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) + throw std::runtime_error("Attempting to create Mipmaps for an image format that does not support blitting"); + + uint32_t destLevel = 1; + VkExtent2D previousExt { extent.width, extent.height }; + + VkTools::immediateExecute([&](const VkCommandBuffer& commands) { + // Blit the new images into place + for (const auto &ext : mipExtents) { + const uint32_t sourceLevel = destLevel - 1; + VkImageMemoryBarrier barrier { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + nullptr, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + 0, 0, image, { VK_IMAGE_ASPECT_COLOR_BIT, sourceLevel, 1, 0, 1 } + }; + + waitForBarrier(commands, barrier, {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT}); + + const VkImageBlit blit { + {VK_IMAGE_ASPECT_COLOR_BIT, sourceLevel, 0, 1}, + {{0, 0, 0}, convertExtent(previousExt)}, + {VK_IMAGE_ASPECT_COLOR_BIT, destLevel, 0, 1}, + {{0, 0, 0}, convertExtent(ext)} + }; + vkCmdBlitImage(commands, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); + + ++destLevel; + previousExt = ext; + } + }, VulkanModule::getInstance()->getDevice()); + + VkTools::immediateExecute([&](const VkCommandBuffer& commands) { + // Convert all images to shader read only so we can sample them + for (uint32_t level = 0; level < mipExtents.size() + 1; ++level) { + VkImageMemoryBarrier barrier { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + nullptr, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, + level == mipExtents.size() ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + 0, 0, image, { VK_IMAGE_ASPECT_COLOR_BIT, level, 1, 0, 1 } + }; + + waitForBarrier(commands, barrier, { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT }); + } + }, VulkanModule::getInstance()->getDevice()); + } + + Image::Image(const VkExtent2D &ext, VkFormat form) : extent(ext), format(form) { + dev = VulkanModule::getInstance()->getDevice(); + } + + void ImageStagingBuffer::copy(const VkImage &target, const VkExtent3D &extent, uint32_t layers) const { + VkTools::immediateExecute([&](const VkCommandBuffer& commands) { + const VkBufferImageCopy copyData { 0, 0, 0, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers }, { 0, 0, 0 }, extent }; + vkCmdCopyBufferToImage(commands, getBuffer(), target, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Data); + }, VulkanModule::getInstance()->getDevice()); + } + + ImageSampler::ImageSampler(int mipLevels, const vlkx::ImageSampler::Config &config) + : sampler(VkTools::createSampler(config.filter, config.mode, mipLevels, VulkanModule::getInstance()->getDevice()->logical)) { + dev = VulkanModule::getInstance()->getDevice(); + } + + Buffer::BulkCopyMeta TextureImage::Meta::getCopyMeta() const { + const VkDeviceSize singleSize = width * height * channels; + const VkDeviceSize totalSize = singleSize * data.size(); + std::vector copy(data.size()); + + // If we're making a framebuffer, we have no data to copy in. + if (data[0] == nullptr) + return { totalSize, {} }; + + for (size_t i = 0; i < copy.size(); ++i) { + copy[i] = { data[i], singleSize, singleSize * i }; + } + + return { totalSize, std::move(copy) }; + } + + TextureImage::TextureImage(bool mipmapping, const ImageSampler::Config &samplerConfig, const vlkx::TextureImage::Meta &meta) + : Image(meta.getExtent(), meta.format), buffer(mipmapping, meta), sampler(buffer.getMipping(), samplerConfig) { + + setView(VkTools::createImageView(buffer.getImage(), format, VK_IMAGE_ASPECT_COLOR_BIT, buffer.getMipping(), meta.data.size(), VulkanModule::getInstance()->getDevice()->logical)); + } + + TextureImage::TextureImage(bool mipmapping, const ImageDescriptor &image, const std::vector& usages, const ImageSampler::Config &config) + : TextureImage(mipmapping, config, createTextureMeta(image, usages)) + {} + + TextureImage::TextureBuffer::TextureBuffer(bool mipmaps, const vlkx::TextureImage::Meta &meta) : ImageBuffer() { + const VkExtent3D extent = expandExtent(meta.getExtent()); + const auto layers = meta.data.size(); + if (layers != 1 && layers != 6) + throw std::runtime_error("Attempting to allocate a texture buffer for an invalid number of textures; only single textures and cubemap textures are supported."); + + ImageConfig config; + config.layers = meta.data.size(); + + std::vector mipExtents; + if (mipmaps) { + mipExtents = getExtentForMipmaps(extent); + mipLevels = mipExtents.size() + 1; + } + + config.mipping = mipLevels; + + VkImageCreateFlags createFlags {}; + if (layers == 6) + createFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + + auto usage = ImageUsage::getFlagsForUsage(meta.usages); + usage |= VK_IMAGE_USAGE_SAMPLED_BIT; + usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + if (mipmaps) usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + setImage(createImage(config, createFlags, meta.format, extent, usage)); + + transitionImage(getImage(), config, VK_IMAGE_ASPECT_COLOR_BIT, { VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL }, { 0, VK_ACCESS_TRANSFER_WRITE_BIT }, { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT }); + + const ImageStagingBuffer staging(meta.getCopyMeta()); + staging.copy(getImage(), extent, config.layers); + + if (mipmaps) { + generateMipmaps(getImage(), meta.format, extent, mipExtents); + } else { + transitionImage(getImage(), config, VK_IMAGE_ASPECT_COLOR_BIT, { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, { VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT }, { VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT }); + } + } + + RefCountedTexture::ReferenceCounter RefCountedTexture::get(const vlkx::RefCountedTexture::ImageLocation &location, const std::vector& usages, const ImageSampler::Config &config) { + bool mips; + const std::string* ident; + std::unique_ptr image; + + if (const auto* singleTex = std::get_if(&location); singleTex != nullptr) { + mips = true; + ident = singleTex; + image = std::make_unique(Image::loadSingleFromDisk(*singleTex, false)); + } else if (const auto* cubeTex = std::get_if(&location); cubeTex != nullptr) { + mips = false; + ident = &cubeTex->directory; + image = std::make_unique(Image::loadCubeFromDisk(cubeTex->directory, cubeTex->files, false)); + } + + return ReferenceCounter::get(*ident, mips, config, createTextureMeta(*image, usages)); + } + + DepthStencilImage::DepthStencilImage(const VkExtent2D &extent) : Image(extent, findFormatForDepthStencil()), buffer(extent, format) { + setView(VkTools::createImageView(getImage(), format, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 1, 1, VulkanModule::getInstance()->getDevice()->logical)); + } + + DepthStencilImage::DepthStencilBuffer::DepthStencilBuffer(const VkExtent2D &extent, VkFormat format) : ImageBuffer() { + setImage(createImage(ImageConfig {}, 0, format, expandExtent(extent), VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)); + } + + SwapchainImage::SwapchainImage(const VkImage &image, const VkExtent2D &extent, VkFormat format) : Image(extent, format), image(image) { + setView(VkTools::createImageView(image, format, VK_IMAGE_ASPECT_COLOR_BIT, 1, 1, VulkanModule::getInstance()->getDevice()->logical)); + managed = { image, nullptr }; + } + + std::unique_ptr MultisampleImage::createColor(const vlkx::Image &targetImage, vlkx::MultisampleImage::Mode mode) { + return std::unique_ptr(new MultisampleImage(targetImage.getExtent(), targetImage.getFormat(), mode, MultisampleBuffer::Type::Color)); + } + + std::unique_ptr MultisampleImage::createDepthStencilMS(const VkExtent2D &extent, vlkx::MultisampleImage::Mode mode) { + return std::unique_ptr(new MultisampleImage(extent, findFormatForDepthStencil(), mode, MultisampleBuffer::Type::DepthStencil)); + } + + std::unique_ptr MultisampleImage::createDepthStencil(VkExtent2D &extent, std::optional mode) { + if (mode.has_value()) + return createDepthStencilMS(extent, mode.value()); + else + return std::make_unique(extent); + } + + MultisampleImage::MultisampleImage(const VkExtent2D &extent, VkFormat format, vlkx::MultisampleImage::Mode mode,MultisampleBuffer::Type type) + : Image(extent, format), samples(chooseSamples(mode)), buffer(type, extent, format, samples) { + + VkImageAspectFlags aspect; + switch (type) { + case MultisampleBuffer::Type::Color: aspect = VK_IMAGE_ASPECT_COLOR_BIT; break; + case MultisampleBuffer::Type::DepthStencil: aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; break; + } + setView(VkTools::createImageView(buffer.getImage(), format, aspect, 1, 1, VulkanModule::getInstance()->getDevice()->logical)); + } + + VkSampleCountFlagBits MultisampleImage::chooseSamples(vlkx::MultisampleImage::Mode mode) { + VkPhysicalDeviceLimits limits; + VkPhysicalDeviceProperties props; + vkGetPhysicalDeviceProperties(VulkanModule::getInstance()->getDevice()->physical, &props); + limits = props.limits; + + const VkSampleCountFlags sampleFlags = std::min({ limits.framebufferColorSampleCounts, limits.framebufferDepthSampleCounts, limits.framebufferStencilSampleCounts }); + const VkSampleCountFlagBits maxSamples = getMaxSamples(sampleFlags); + switch (mode) { + case Mode::MostEfficient: return std::min(VK_SAMPLE_COUNT_4_BIT, maxSamples); + case Mode::Highest: return maxSamples; + } + } + + MultisampleImage::MultisampleBuffer::MultisampleBuffer(vlkx::MultisampleImage::MultisampleBuffer::Type type, const VkExtent2D &extent, VkFormat format, VkSampleCountFlagBits samples) + : ImageBuffer() { + + VkImageUsageFlags usageFlags; + switch (type) { + case Type::Color: usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; break; + case Type::DepthStencil: usageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; break; + } + + ImageConfig config; + config.samples = samples; + + setImage(createImage(config, 0, format, expandExtent(extent), usageFlags)); + + } + +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-utility/inc/shadow/util/File.h b/projs/shadow/shadow-engine/shadow-utility/inc/shadow/util/File.h new file mode 100644 index 0000000..14a94ac --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-utility/inc/shadow/util/File.h @@ -0,0 +1,13 @@ +#pragma once +#include +#include +namespace shadowutil { + + struct FileData { + size_t size; + std::vector data; + }; + + // A testing stub; this should be deleted and wired into the asset system once that becomes ready. + FileData* loadFile(std::string path); +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-utility/inc/shadow/util/RefCounter.h b/projs/shadow/shadow-engine/shadow-utility/inc/shadow/util/RefCounter.h new file mode 100644 index 0000000..87400dd --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-utility/inc/shadow/util/RefCounter.h @@ -0,0 +1,121 @@ +#pragma once + +#include +#include +#include + +namespace shadowutil { + + // An object wrapper that behaves like smart pointers. + // References to this object are counted, and the object will be destructed when there are no references. + // This allows for automatic, safe and leak-free handling of all kinds of resources. + // The AutoRelease behaviour can be adjusted. + template + class RefCounter { + public: + + // Preserves ObjectType instances in the current scope. + // Use like lock_guard; RAII allows precise scoping rules. + class AutoRelease { + public: + explicit AutoRelease() { RefCounter::registerAutoRelease(); } + + AutoRelease(const AutoRelease&) = delete; + AutoRelease& operator=(const AutoRelease&) = delete; + + ~AutoRelease() { RefCounter::unregisterAutoRelease(); } + + // AutoRelease can only exist on the stack. + void* operator new(size_t) = delete; + void* operator new[](size_t) = delete; + }; + + // Use to access a ref counted object. + // If exists, the object will be passed and reference counter increased. + // Otherwise, args will be used to create. + template + static RefCounter get(const std::string& identifier, Args&&... args) { + auto iter = getMap().find(identifier); + if (iter == getMap().end()) { + const auto inserted = getMap().insert( + { + identifier, + typename ObjectPool::CountedObject { + std::make_unique(std::forward(args)...), 0 + } + } + ); + iter = inserted.first; + } + + auto& object = iter->second; + ++object.references; + return RefCounter { identifier, object.obj.get() }; + } + + RefCounter(RefCounter&& other) noexcept { + identifier = std::move(other.identifier); + objectPtr = other.objectPtr; + other.identifier.clear(); + } + + RefCounter& operator=(RefCounter&& other) noexcept { + std::swap(identifier, other.identifier); + std::swap(objectPtr, other.objectPtr); + return *this; + } + + // When we reach 0 references and there's no auto release system set up, destroy the object. + ~RefCounter() { + if (identifier.empty()) return; + + const auto iter = getMap().find(identifier); + if (--iter->second.references == 0 && objectPool.activePools == 0) + getMap().erase(iter); + } + + // Smart pointer emulation overloads. + const ObjectType* operator->() const { return objectPtr; } + const ObjectType& operator*() const { return *objectPtr; } + + static bool hasAutoRelease() { return objectPool.activePools != 0; } + + private: + // The object pool that handles managing and counting objects. + struct ObjectPool { + struct CountedObject { + std::unique_ptr obj; + size_t references; + }; + + using RefCountMap = std::map; + + RefCountMap refCountMap; + size_t activePools = 0; + }; + + RefCounter(std::string identifier, const ObjectType* obj) : identifier(std::move(identifier)), objectPtr(obj) {} + + static void unregisterAutoRelease() { + if (--objectPool.activePools == 0) { + using CountedObject = typename ObjectPool::CountedObject; + static const auto removeZeroRef = [](const std::pair &pair) { + return pair.second.references == 0; + }; + std::erase_if(getMap(), removeZeroRef); + } + } + + static void registerAutoRelease() { ++objectPool.activePools; } + + static typename ObjectPool::RefCountMap& getMap() { return objectPool.refCountMap; } + + static ObjectPool objectPool; + + std::string identifier; + const ObjectType* objectPtr; + }; + + template + typename RefCounter::ObjectPool RefCounter::objectPool {}; +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-utility/inc/stb_image.h b/projs/shadow/shadow-engine/shadow-utility/inc/stb_image.h new file mode 100644 index 0000000..622061a --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-utility/inc/stb_image.h @@ -0,0 +1,7897 @@ +/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine Simon Breuss (16-bit PNM) + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR +STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif +#endif + +#ifndef STBI_NO_HDR +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); +STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); +STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) + return 0; + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_global = flag_true_if_should_convert; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind( s ); + return 0; + } + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/projs/shadow/shadow-engine/shadow-utility/src/string-helpers.h b/projs/shadow/shadow-engine/shadow-utility/inc/string-helpers.h similarity index 100% rename from projs/shadow/shadow-engine/shadow-utility/src/string-helpers.h rename to projs/shadow/shadow-engine/shadow-utility/inc/string-helpers.h diff --git a/projs/shadow/shadow-engine/shadow-utility/src/File.cpp b/projs/shadow/shadow-engine/shadow-utility/src/File.cpp new file mode 100644 index 0000000..cf20d6a --- /dev/null +++ b/projs/shadow/shadow-engine/shadow-utility/src/File.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +namespace shadowutil { + FileData* loadFile(std::string path) { + // Verify the file + std::ifstream file(path, std::ios::binary | std::ios::ate); + + if (!file.is_open()) + throw std::runtime_error("Unable to open specified file: " + std::string(path)); + + auto* data = new FileData {}; + + // Read the file's size (opened with At The End, so just tellg the size) + size_t size = file.tellg(); + data->data.resize(size); + data->size = size; + // Go to the front of the file + file.seekg(0); + // Read the file into the buffer + file.read(data->data.data(), size); + file.close(); + + return data; + } +} \ No newline at end of file diff --git a/projs/shadow/shadow-engine/shadow-utility/src/string-helpers.cpp b/projs/shadow/shadow-engine/shadow-utility/src/string-helpers.cpp index 8c0ae0e..d7a82f6 100644 --- a/projs/shadow/shadow-engine/shadow-utility/src/string-helpers.cpp +++ b/projs/shadow/shadow-engine/shadow-utility/src/string-helpers.cpp @@ -1,5 +1,5 @@ -#include "string-helpers.h" +#include "../inc/string-helpers.h" std::vector explode(const std::string& s, const char& c) { diff --git a/projs/shadow/shadow-runtime/CMakeLists.txt b/projs/shadow/shadow-runtime/CMakeLists.txt index 8f953ee..a70601b 100644 --- a/projs/shadow/shadow-runtime/CMakeLists.txt +++ b/projs/shadow/shadow-runtime/CMakeLists.txt @@ -8,7 +8,6 @@ add_executable(shadow-runtime ${SOURCES}) target_include_directories(shadow-runtime PRIVATE ${SDL2_INCLUDE_DIRS}) target_link_libraries(shadow-runtime PRIVATE SDL2::SDL2main PUBLIC shadow-engine) - add_custom_command(TARGET shadow-runtime POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ $ COMMAND_EXPAND_LISTS diff --git a/projs/test-game/inc/GameModule.h b/projs/test-game/inc/GameModule.h index 2706956..b3430f7 100644 --- a/projs/test-game/inc/GameModule.h +++ b/projs/test-game/inc/GameModule.h @@ -13,13 +13,17 @@ public: void Init() override; - void Update() override; + void Update(int frame) override; void PreRender() override; - void Render() override; + void Recreate() override; - void LateRender() override; + void OverlayRender() override; + + void Render(VkCommandBuffer& commands, int frame) override; + + void LateRender(VkCommandBuffer& commands, int frame) override; void AfterFrameEnd() override; diff --git a/projs/test-game/src/GameModule.cpp b/projs/test-game/src/GameModule.cpp index 517ad27..0e78683 100644 --- a/projs/test-game/src/GameModule.cpp +++ b/projs/test-game/src/GameModule.cpp @@ -1,171 +1,92 @@ #include #include "imgui.h" #include "spdlog/spdlog.h" -#include "vlkx/render/geometry/SingleRenderer.h" #include "imgui_impl_vulkan.h" -#include "core/ShadowApplication.h" -#include "core/SDL2Module.h" #include "imgui_impl_sdl.h" #include "core/Time.h" - +#include "vlkx/render/Camera.h" +#include "vlkx/vulkan/abstraction/Buffer.h" +#include "vlkx/render/render_pass/ScreenRenderPass.h" +#include "temp/model/Builder.h" +#include "core/ModuleManager.h" #define CATCH(x) \ try { x } catch (std::exception& e) { spdlog::error(e.what()); exit(0); } -// Create the renderer -SingleRenderer object; - -// Create the camera -Camera camera; - SHObject_Base_Impl(GameModule) -void GameModule::PreInit() { spdlog::info("Game Module loading.."); } +struct Transformation { + alignas(sizeof(glm::mat4)) glm::mat4 proj_view_model; +}; + +std::unique_ptr trans_constant_; +std::unique_ptr cube_model_; +float aspectRatio; + +void GameModule::PreInit() { } void GameModule::Init() { + spdlog::info("Game Module loading level.."); + trans_constant_ = std::make_unique( + sizeof(Transformation), 2); - auto shApp = ShadowEngine::ShadowApplication::Get(); + auto extent = ShadowEngine::ModuleManager::getInstance()->renderer->GetRenderExtent(); + aspectRatio = (float) extent.width / extent.height; - ShadowEngine::ModuleManager &moduleManager = shApp.GetModuleManager(); + /* Model */ + cube_model_ = vlkxtemp::ModelBuilder { + "Walrus", 2, aspectRatio, + vlkxtemp::ModelBuilder::SingleMeshModel {"resources/walrus/walrus.obj", 1, + {{ vlkxtemp::ModelBuilder::TextureType::Diffuse, { { "resources/walrus/texture.png" } } } } + }} + .bindTextures(vlkxtemp::ModelBuilder::TextureType::Diffuse, 1) + .pushStage(VK_SHADER_STAGE_VERTEX_BIT) + .pushConstant(trans_constant_.get(), 0) + .shader(VK_SHADER_STAGE_VERTEX_BIT, "resources/walrus/cube.vert.spv") + .shader(VK_SHADER_STAGE_FRAGMENT_BIT, "resources/walrus/cube.frag.spv") + .build(); - auto sdl2module = moduleManager.GetModuleByType(); - - CATCH(VulkanManager::getInstance()->initVulkan(sdl2module->_window->sdlWindowPtr);) - - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking - io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows - - // Setup Dear ImGui style - ImGui::StyleColorsDark(); - VkDescriptorPool imGuiPool; - VulkanManager* vk = VulkanManager::getInstance(); - VkDescriptorPoolSize pool_sizes[] = - { - { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, - { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, - { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } - }; - - VkDescriptorPoolCreateInfo pool_info = {}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes); - pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); - pool_info.pPoolSizes = pool_sizes; - vkCreateDescriptorPool(vk->getDevice()->logical, &pool_info, VK_NULL_HANDLE, &imGuiPool); - - // Setup Platform/Renderer backends - ImGui_ImplSDL2_InitForVulkan(sdl2module->_window->sdlWindowPtr); - ImGui_ImplVulkan_InitInfo init_info = {}; - init_info.Instance = vk->getVulkan(); - init_info.PhysicalDevice = vk->getDevice()->physical; - init_info.Device = vk->getDevice()->logical; - init_info.QueueFamily = vk->getDevice()->queueData.graphics; - init_info.Queue = vk->getDevice()->graphicsQueue; - init_info.PipelineCache = VK_NULL_HANDLE; - init_info.DescriptorPool = imGuiPool; - init_info.Subpass = 0; - init_info.MinImageCount = vk->getSwapchain()->images.size(); - init_info.ImageCount = vk->getSwapchain()->images.size(); - init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; - init_info.Allocator = VK_NULL_HANDLE; - init_info.CheckVkResultFn = nullptr; - ImGui_ImplVulkan_Init(&init_info, vk->getRenderPass()->pass); - - // Upload Fonts - { - // Prepare to create a temporary command pool. - VkCommandPool pool; - VkCommandPoolCreateInfo poolCreateInfo = {}; - poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolCreateInfo.queueFamilyIndex = vk->getDevice()->queueData.graphics; - poolCreateInfo.flags = 0; - - // Create the pool - if (vkCreateCommandPool(vk->getDevice()->logical, &poolCreateInfo, nullptr, &pool) != VK_SUCCESS) - throw std::runtime_error("Unable to allocate a temporary command pool"); - - VkCommandBuffer buffer = VkTools::createTempCommandBuffer(pool, vk->getDevice()->logical); - - ImGui_ImplVulkan_CreateFontsTexture(buffer); - - VkSubmitInfo end_info = {}; - end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - end_info.commandBufferCount = 1; - end_info.pCommandBuffers = &buffer; - - VkTools::executeAndDeleteTempBuffer(buffer, pool, vk->getDevice()->graphicsQueue, vk->getDevice()->logical); - - ImGui_ImplVulkan_DestroyFontUploadObjects(); - } - - CATCH(object.createSingleRenderer(Geo::MeshType::Cube, glm::vec3(-1, 0, -1), glm::vec3(0.5));) - camera.init(45, 1280, 720, 0.1, 10000); - camera.setPosition(glm::vec3(0, 0, 4)); + Recreate(); } -void GameModule::Update() { - object.setRotation(glm::rotate(object.getRotation(), (float) 0.5, glm::vec3(1, 0, 0))); +void GameModule::Recreate() { + auto extent = ShadowEngine::ModuleManager::getInstance()->renderer->GetRenderExtent(); + cube_model_->update(true, extent, VK_SAMPLE_COUNT_1_BIT, *VulkanModule::getInstance()->getRenderPass()->getPass(), 0); } -void GameModule::PreRender() { - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - ImGui::NewFrame(); +void GameModule::Update(int frame) { + const float elapsed_time = Time::timeSinceStart; + const glm::mat4 model = glm::rotate(glm::mat4{1.0f}, + (elapsed_time / 1000 / 2) * glm::radians(90.0f), + glm::vec3{1.0f, 1.0f, 0.0f}); + const glm::mat4 view = glm::lookAt(glm::vec3{3.0f}, glm::vec3{0.0f}, + glm::vec3{0.0f, 0.0f, 1.0f}); + const glm::mat4 proj = glm::perspective( + glm::radians(45.0f), aspectRatio, + 0.1f, 100.0f); + *trans_constant_->getData(frame) = {proj * view * model}; } -void GameModule::Render() { +void GameModule::Render(VkCommandBuffer& commands, int frame) { + cube_model_->draw(commands, frame, 1); +} + +void GameModule::OverlayRender() { bool active = true; - ImGui::Begin("Game module window", &active, ImGuiWindowFlags_MenuBar); - - ImGui::Text("Such teext from curle's branch"); - + if (ImGui::Begin("Game module window", &active, ImGuiWindowFlags_MenuBar)) + ImGui::Text("Such text from curle's branch"); ImGui::End(); - CATCH(object.updateUniforms(camera);) - CATCH(object.draw();) - - bool showDemo = true; - if (showDemo) - ImGui::ShowDemoWindow(&showDemo); - -} - -void GameModule::LateRender() { - ImGui::Render(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), VulkanManager::getInstance()->getCurrentCommandBuffer()); - - // Update and Render additional Platform Windows - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); - } + bool open = false; + ImGui::ShowDemoWindow(&open); } void GameModule::AfterFrameEnd() { Time::UpdateTime(); } -void GameModule::Destroy() { - ImGui_ImplVulkan_Shutdown(); - ImGui_ImplSDL2_Shutdown(); - ImGui::DestroyContext(); -} +void GameModule::LateRender(VkCommandBuffer& commands, int frame) {} +void GameModule::PreRender() {} -void GameModule::Event(SDL_Event *) { - -} \ No newline at end of file +void GameModule::Destroy() {} +void GameModule::Event(SDL_Event *) {} \ No newline at end of file diff --git a/projs/test-game/src/entry.cpp b/projs/test-game/src/entry.cpp index 1db046f..f36f5b0 100644 --- a/projs/test-game/src/entry.cpp +++ b/projs/test-game/src/entry.cpp @@ -7,19 +7,8 @@ #include "core/ShadowApplication.h" #include "GameModule.h" #include "core/ShadowApplication.h" -#include "vlkx/vulkan/VulkanManager.h" +#include "vlkx/vulkan/VulkanModule.h" extern "C" __declspec(dllexport) void shadow_main(ShadowEngine::ShadowApplication* app) { - - std::cout << "HIIII from a loaded dll weeeeeee!!!" << std::endl; - app->GetModuleManager().PushModule(std::make_shared(), "game"); - - if(app == &ShadowEngine::ShadowApplication::Get()){ - std::cout << "They are the same!!!" << std::endl; - } - - printf("dll side: %p \n", VulkanManager::getInstance()); - printf("dll next ID: %llu \n", ShadowEngine::SHObject::GenerateId()); - } diff --git a/resources/planets/skybox.frag b/resources/planets/skybox.frag new file mode 100644 index 0000000..693740c --- /dev/null +++ b/resources/planets/skybox.frag @@ -0,0 +1,10 @@ +#version 460 core + +layout(binding = 1) uniform samplerCube tex; + +layout(location = 0) in vec3 tex_coord; +layout(location = 0) out vec4 frag_color; + +void main() { + frag_color = texture(tex, tex_coord); +} \ No newline at end of file diff --git a/resources/planets/skybox.vert b/resources/planets/skybox.vert new file mode 100644 index 0000000..c42a46c --- /dev/null +++ b/resources/planets/skybox.vert @@ -0,0 +1,18 @@ +#version 450 + +layout(std140, push_constant) uniform Transform { + mat4 matrix; +} transf; + +layout(location = 0) in vec3 in_pos; +layout(location = 1) in vec3 in_normal; +layout(location = 2) in vec2 in_uv; + +layout(location = 0) out vec3 texCoord; + +void main() { + + gl_Position = transf.matrix * vec4(in_pos, 1.0); + gl_Position.zw = vec2(1.0); + texCoord = in_pos; +} \ No newline at end of file diff --git a/resources/tri/tri.frag b/resources/tri/tri.frag new file mode 100644 index 0000000..8935b06 --- /dev/null +++ b/resources/tri/tri.frag @@ -0,0 +1,13 @@ +#version 450 + +layout(push_constant) uniform Alpha { + float value; +} alpha; + +layout(location = 0) in vec3 color; + +layout(location = 0) out vec4 frag_color; + +void main() { + frag_color = vec4(color, alpha.value); +} \ No newline at end of file diff --git a/resources/tri/tri.frag.spv b/resources/tri/tri.frag.spv new file mode 100644 index 0000000..013bd92 Binary files /dev/null and b/resources/tri/tri.frag.spv differ diff --git a/resources/tri/tri.vert b/resources/tri/tri.vert new file mode 100644 index 0000000..d2d100e --- /dev/null +++ b/resources/tri/tri.vert @@ -0,0 +1,11 @@ +#version 450 + +layout(location = 0) in vec3 in_pos; +layout(location = 1) in vec3 in_color; + +layout(location = 0) out vec3 color; + +void main() { + gl_Position = vec4(in_pos, 1.0); + color = in_color; +} \ No newline at end of file diff --git a/resources/tri/tri.vert.spv b/resources/tri/tri.vert.spv new file mode 100644 index 0000000..7da1813 Binary files /dev/null and b/resources/tri/tri.vert.spv differ diff --git a/resources/walrus/cube.frag b/resources/walrus/cube.frag new file mode 100644 index 0000000..daa961d --- /dev/null +++ b/resources/walrus/cube.frag @@ -0,0 +1,10 @@ +#version 450 + +layout(binding = 1) uniform sampler2D tex; + +layout(location = 0) in vec2 tex_coord; +layout(location = 0) out vec4 frag_color; + +void main() { + frag_color = texture(tex, tex_coord); +} \ No newline at end of file diff --git a/resources/walrus/cube.frag.spv b/resources/walrus/cube.frag.spv new file mode 100644 index 0000000..910efd7 Binary files /dev/null and b/resources/walrus/cube.frag.spv differ diff --git a/resources/walrus/cube.vert b/resources/walrus/cube.vert new file mode 100644 index 0000000..ea2110f --- /dev/null +++ b/resources/walrus/cube.vert @@ -0,0 +1,16 @@ +#version 450 + +layout(std140, push_constant) uniform Transform { + mat4 matrix; +} transf; + +layout(location = 0) in vec3 in_pos; +layout(location = 1) in vec3 in_normal; +layout(location = 2) in vec2 in_uv; + +layout(location = 0) out vec2 texCoord; + +void main() { + gl_Position = transf.matrix * vec4(in_pos, 1.0); + texCoord = in_uv; +} \ No newline at end of file diff --git a/resources/walrus/cube.vert.spv b/resources/walrus/cube.vert.spv new file mode 100644 index 0000000..accf4a6 Binary files /dev/null and b/resources/walrus/cube.vert.spv differ diff --git a/resources/walrus/texture.png b/resources/walrus/texture.png new file mode 100644 index 0000000..7e6ef55 Binary files /dev/null and b/resources/walrus/texture.png differ diff --git a/resources/walrus/walrus.obj b/resources/walrus/walrus.obj new file mode 100644 index 0000000..da4977e --- /dev/null +++ b/resources/walrus/walrus.obj @@ -0,0 +1,12745 @@ +# Blender v2.78 (sub 0) OBJ File: '' +# www.blender.org +v 0.583243 0.877305 0.542592 +v 0.585834 0.873988 0.547622 +v 0.590746 0.870400 0.543599 +v 0.576904 0.879000 0.547994 +v 0.580394 0.875442 0.552257 +v 0.594651 0.865029 0.540583 +v 0.593519 0.866864 0.534390 +v 0.588969 0.873123 0.537905 +v 0.564864 0.874525 0.558808 +v 0.570063 0.871603 0.561536 +v 0.570571 0.878042 0.553582 +v 0.566183 0.866684 0.565271 +v 0.560343 0.868794 0.563160 +v 0.574959 0.874620 0.557052 +v 0.591346 0.856352 0.558106 +v 0.590253 0.857855 0.558949 +v 0.587822 0.852797 0.562342 +v 0.592049 0.854498 0.557626 +v 0.592295 0.852473 0.557557 +v 0.587357 0.859266 0.561372 +v 0.585836 0.859036 0.562713 +v 0.588879 0.858859 0.560075 +v 0.596450 0.859140 0.532392 +v 0.597166 0.858400 0.538869 +v 0.597474 0.850707 0.532107 +v 0.597142 0.846018 0.546752 +v 0.597202 0.844028 0.539873 +v 0.598045 0.851164 0.538624 +v 0.597809 0.851663 0.545764 +v 0.585941 0.829754 0.550713 +v 0.580507 0.828933 0.555507 +v 0.577036 0.824800 0.551782 +v 0.590838 0.832772 0.546229 +v 0.583369 0.825758 0.546195 +v 0.589076 0.829274 0.540969 +v 0.575067 0.830387 0.560143 +v 0.570697 0.826495 0.557184 +v 0.596491 0.842391 0.533563 +v 0.594718 0.837691 0.542493 +v 0.593597 0.835006 0.536616 +v 0.556466 0.853092 0.567669 +v 0.562856 0.853211 0.569140 +v 0.563699 0.860347 0.567891 +v 0.563734 0.845975 0.568896 +v 0.557490 0.844660 0.567384 +v 0.557449 0.861408 0.566214 +v 0.564971 0.830676 0.561872 +v 0.570154 0.833975 0.564166 +v 0.560421 0.836936 0.565387 +v 0.566249 0.839346 0.567182 +v 0.591729 0.842023 0.556112 +v 0.592109 0.837116 0.551779 +v 0.595177 0.841006 0.548824 +v 0.588236 0.834729 0.555325 +v 0.593852 0.844715 0.554067 +v 0.586074 0.839922 0.561190 +v 0.583937 0.834079 0.559118 +v 0.579635 0.835229 0.562784 +v 0.589049 0.840372 0.558566 +v 0.595125 0.862628 0.547313 +v 0.597114 0.857386 0.545958 +v 0.595673 0.852090 0.551950 +v 0.595212 0.848184 0.552633 +v 0.583097 0.840718 0.563727 +v 0.570643 0.858926 0.568913 +v 0.576875 0.857116 0.567968 +v 0.578234 0.860584 0.566534 +v 0.572607 0.863938 0.566840 +v 0.569976 0.853281 0.569901 +v 0.576413 0.853210 0.568652 +v 0.575676 0.867828 0.563886 +v 0.580358 0.863276 0.564490 +v 0.579549 0.870215 0.560339 +v 0.583038 0.864928 0.562035 +v 0.575749 0.838067 0.565966 +v 0.580408 0.842682 0.565929 +v 0.572660 0.842315 0.568351 +v 0.578271 0.845622 0.567580 +v 0.570671 0.847558 0.569707 +v 0.576894 0.849249 0.568518 +v 0.583847 0.870865 0.556547 +v 0.588150 0.869715 0.552880 +v 0.592036 0.866877 0.549699 +v 0.588990 0.864581 0.556874 +v 0.586012 0.865378 0.559411 +v 0.591679 0.862617 0.554673 +v 0.593816 0.859678 0.553022 +v 0.582686 0.855042 0.565746 +v 0.583381 0.856815 0.565013 +v 0.584467 0.858191 0.563968 +v 0.595192 0.856050 0.552084 +v 0.582696 0.851021 0.566027 +v 0.583400 0.849167 0.565547 +v 0.582450 0.853046 0.566095 +v 0.584492 0.847664 0.564703 +v 0.585867 0.846660 0.563578 +v 0.592059 0.850477 0.557907 +v 0.591365 0.848704 0.558640 +v 0.587389 0.846253 0.562281 +v 0.588909 0.846483 0.560940 +v 0.590279 0.847328 0.559685 +v 0.431942 0.853281 0.569901 +v 0.431247 0.847558 0.569707 +v 0.439062 0.853211 0.569140 +v 0.431275 0.858926 0.568913 +v 0.438184 0.845975 0.568896 +v 0.429258 0.842315 0.568351 +v 0.435669 0.839346 0.567182 +v 0.438219 0.860347 0.567891 +v 0.426242 0.867828 0.563886 +v 0.429311 0.863938 0.566840 +v 0.431855 0.871603 0.561536 +v 0.426959 0.874620 0.557052 +v 0.435735 0.866684 0.565271 +v 0.413682 0.834729 0.555325 +v 0.415977 0.829754 0.550713 +v 0.421411 0.828933 0.555507 +v 0.417981 0.834079 0.559118 +v 0.409809 0.837116 0.551779 +v 0.411080 0.832772 0.546229 +v 0.407200 0.837691 0.542493 +v 0.422283 0.835229 0.562784 +v 0.426169 0.838067 0.565966 +v 0.431764 0.833975 0.564166 +v 0.426851 0.830387 0.560143 +v 0.422369 0.870215 0.560339 +v 0.406706 0.848184 0.552633 +v 0.404776 0.846018 0.546752 +v 0.408066 0.844715 0.554067 +v 0.406741 0.841006 0.548824 +v 0.406245 0.852090 0.551950 +v 0.404109 0.851663 0.545764 +v 0.404804 0.857386 0.545958 +v 0.403873 0.851164 0.538624 +v 0.410189 0.842023 0.556112 +v 0.412869 0.840372 0.558566 +v 0.415844 0.839922 0.561190 +v 0.418071 0.870865 0.556547 +v 0.421524 0.875442 0.552257 +v 0.413768 0.869715 0.552880 +v 0.416084 0.873988 0.547622 +v 0.409882 0.866877 0.549699 +v 0.411172 0.870400 0.543599 +v 0.406793 0.862628 0.547313 +v 0.404752 0.858400 0.538869 +v 0.407267 0.865029 0.540583 +v 0.436947 0.830676 0.561872 +v 0.441497 0.836936 0.565387 +v 0.431221 0.826495 0.557184 +v 0.424882 0.824800 0.551782 +v 0.444428 0.844660 0.567384 +v 0.445452 0.853092 0.567669 +v 0.444469 0.861408 0.566214 +v 0.408321 0.835006 0.536616 +v 0.405427 0.842391 0.533563 +v 0.404716 0.844028 0.539873 +v 0.404444 0.850707 0.532107 +v 0.412842 0.829274 0.540969 +v 0.418549 0.825758 0.546195 +v 0.405468 0.859140 0.532392 +v 0.408399 0.866864 0.534390 +v 0.412949 0.873123 0.537905 +v 0.437054 0.874525 0.558808 +v 0.431347 0.878042 0.553582 +v 0.441575 0.868794 0.563160 +v 0.425014 0.879000 0.547994 +v 0.418675 0.877305 0.542592 +v 0.414561 0.859266 0.561372 +v 0.416082 0.859036 0.562713 +v 0.415906 0.865378 0.559411 +v 0.413039 0.858859 0.560075 +v 0.418880 0.864928 0.562035 +v 0.417451 0.858191 0.563968 +v 0.421560 0.863276 0.564490 +v 0.412928 0.864581 0.556874 +v 0.410572 0.856352 0.558106 +v 0.411665 0.857855 0.558949 +v 0.408102 0.859678 0.553022 +v 0.409869 0.854498 0.557626 +v 0.410239 0.862617 0.554673 +v 0.419222 0.851021 0.566027 +v 0.425024 0.849249 0.568518 +v 0.425505 0.853210 0.568652 +v 0.419468 0.853046 0.566095 +v 0.423647 0.845622 0.567580 +v 0.418518 0.849167 0.565547 +v 0.421510 0.842682 0.565929 +v 0.419232 0.855042 0.565746 +v 0.418537 0.856815 0.565013 +v 0.423684 0.860584 0.566534 +v 0.425043 0.857116 0.567968 +v 0.406726 0.856050 0.552084 +v 0.414096 0.852797 0.562342 +v 0.409623 0.852473 0.557557 +v 0.409859 0.850477 0.557907 +v 0.410553 0.848704 0.558640 +v 0.411639 0.847328 0.559685 +v 0.413009 0.846483 0.560940 +v 0.417426 0.847664 0.564703 +v 0.416051 0.846660 0.563578 +v 0.414529 0.846253 0.562281 +v 0.418821 0.840718 0.563727 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vn 0.5724 0.7884 0.2251 +vn 0.5937 0.7587 0.2680 +vn 0.7570 0.6395 0.1343 +vn 0.3836 0.8389 0.3861 +vn 0.4129 0.8070 0.4221 +vn 0.8867 0.4610 0.0341 +vn 0.8784 0.4775 -0.0191 +vn 0.7429 0.6639 0.0856 +vn 0.0250 0.7056 0.7081 +vn 0.0696 0.6794 0.7304 +vn 0.1950 0.8104 0.5525 +vn -0.0593 0.5160 0.8545 +vn -0.1095 0.5349 0.8377 +vn 0.2324 0.7797 0.5814 +vn 0.7729 0.1729 0.6105 +vn 0.7365 0.2231 0.6386 +vn 0.6560 0.0542 0.7528 +vn 0.7965 0.1108 0.5944 +vn 0.8047 0.0433 0.5921 +vn 0.6396 0.2702 0.7196 +vn 0.5889 0.2626 0.7643 +vn 0.6906 0.2565 0.6761 +vn 0.9657 0.2474 -0.0785 +vn 0.9703 0.2407 -0.0228 +vn 0.9962 -0.0036 -0.0870 +vn 0.9625 -0.1793 0.2034 +vn 0.9715 -0.2369 0.0105 +vn 0.9995 0.0003 -0.0310 +vn 0.9854 0.0143 0.1695 +vn 0.5972 -0.7112 0.3708 +vn 0.4167 -0.7385 0.5301 +vn 0.3875 -0.7752 0.4989 +vn 0.7600 -0.6109 0.2217 +vn 0.5761 -0.7467 0.3325 +vn 0.7461 -0.6419 0.1769 +vn 0.2360 -0.6902 0.6840 +vn 0.1987 -0.7247 0.6597 +vn 0.9669 -0.2513 -0.0437 +vn 0.8889 -0.4474 0.0976 +vn 0.8807 -0.4712 0.0473 +vn -0.2250 0.0674 0.9720 +vn -0.1698 0.0683 0.9831 +vn -0.1418 0.3054 0.9416 +vn -0.1406 -0.1721 0.9750 +vn -0.1946 -0.1837 0.9635 +vn -0.1957 0.3150 0.9287 +vn 0.0282 -0.6002 0.7993 +vn 0.0727 -0.5709 0.8177 +vn -0.1073 -0.4137 0.9040 +vn -0.0571 -0.3924 0.9180 +vn 0.7818 -0.2966 0.5484 +vn 0.7900 -0.4845 0.3757 +vn 0.8952 -0.3511 0.2744 +vn 0.6571 -0.5664 0.4973 +vn 0.8510 -0.2090 0.4818 +vn 0.5977 -0.3651 0.7137 +vn 0.5098 -0.5886 0.6273 +vn 0.3623 -0.5492 0.7530 +vn 0.6945 -0.3504 0.6284 +vn 0.8934 0.3902 0.2225 +vn 0.9616 0.2105 0.1761 +vn 0.9102 0.0311 0.4129 +vn 0.8952 -0.0961 0.4352 +vn 0.5008 -0.3392 0.7963 +vn 0.0539 0.2633 0.9632 +vn 0.2983 0.1947 0.9344 +vn 0.3424 0.3076 0.8877 +vn 0.1213 0.4352 0.8921 +vn 0.0310 0.0697 0.9971 +vn 0.2832 0.0675 0.9567 +vn 0.2265 0.5685 0.7908 +vn 0.4116 0.3952 0.8212 +vn 0.3593 0.6504 0.6692 +vn 0.4989 0.4490 0.7412 +vn 0.2291 -0.4519 0.8621 +vn 0.4133 -0.2752 0.8680 +vn 0.1231 -0.3062 0.9439 +vn 0.3437 -0.1795 0.9218 +vn 0.0549 -0.1265 0.9904 +vn 0.2988 -0.0614 0.9523 +vn 0.5067 0.6727 0.5392 +vn 0.6542 0.6332 0.4135 +vn 0.7875 0.5359 0.3044 +vn 0.6926 0.4378 0.5732 +vn 0.5957 0.4637 0.6558 +vn 0.7801 0.3738 0.5016 +vn 0.8498 0.2781 0.4478 +vn 0.4837 0.1291 0.8657 +vn 0.5068 0.1883 0.8412 +vn 0.5433 0.2344 0.8062 +vn 0.8946 0.1599 0.4173 +vn 0.4840 -0.0051 0.8750 +vn 0.5076 -0.0671 0.8589 +vn 0.4758 0.0625 0.8773 +vn 0.5440 -0.1172 0.8309 +vn 0.5898 -0.1507 0.7933 +vn 0.7968 -0.0232 0.6038 +vn 0.7736 -0.0825 0.6283 +vn 0.6408 -0.1644 0.7499 +vn 0.6916 -0.1567 0.7051 +vn 0.7373 -0.1285 0.6632 +vn -0.0310 0.0697 0.9971 +vn -0.0549 -0.1265 0.9904 +vn 0.1698 0.0683 0.9831 +vn -0.0539 0.2633 0.9632 +vn 0.1406 -0.1721 0.9750 +vn -0.1231 -0.3062 0.9440 +vn 0.0571 -0.3924 0.9180 +vn 0.1418 0.3054 0.9416 +vn -0.2265 0.5685 0.7908 +vn -0.1213 0.4352 0.8921 +vn -0.0696 0.6794 0.7304 +vn -0.2324 0.7797 0.5814 +vn 0.0593 0.5160 0.8545 +vn -0.6571 -0.5664 0.4973 +vn -0.5972 -0.7112 0.3707 +vn -0.4167 -0.7385 0.5301 +vn -0.5098 -0.5886 0.6273 +vn -0.7900 -0.4845 0.3757 +vn -0.7600 -0.6109 0.2217 +vn -0.8889 -0.4474 0.0976 +vn -0.3623 -0.5492 0.7530 +vn -0.2291 -0.4519 0.8621 +vn -0.0727 -0.5709 0.8177 +vn -0.2360 -0.6902 0.6841 +vn -0.3593 0.6504 0.6692 +vn -0.8952 -0.0961 0.4352 +vn -0.9625 -0.1793 0.2034 +vn -0.8510 -0.2090 0.4818 +vn -0.8952 -0.3511 0.2744 +vn -0.9102 0.0311 0.4129 +vn -0.9854 0.0143 0.1695 +vn -0.9616 0.2105 0.1761 +vn -0.9995 0.0003 -0.0310 +vn -0.7818 -0.2966 0.5484 +vn -0.6945 -0.3504 0.6284 +vn -0.5977 -0.3651 0.7137 +vn -0.5067 0.6727 0.5392 +vn -0.4129 0.8070 0.4221 +vn -0.6542 0.6332 0.4135 +vn -0.5937 0.7587 0.2680 +vn -0.7875 0.5359 0.3044 +vn -0.7570 0.6395 0.1343 +vn -0.8934 0.3902 0.2225 +vn -0.9703 0.2407 -0.0228 +vn -0.8867 0.4610 0.0341 +vn -0.0282 -0.6002 0.7993 +vn 0.1073 -0.4137 0.9040 +vn -0.1987 -0.7247 0.6597 +vn -0.3875 -0.7752 0.4989 +vn 0.1946 -0.1837 0.9635 +vn 0.2250 0.0674 0.9720 +vn 0.1957 0.3150 0.9287 +vn -0.8807 -0.4712 0.0473 +vn -0.9669 -0.2513 -0.0437 +vn -0.9715 -0.2369 0.0105 +vn -0.9962 -0.0036 -0.0870 +vn -0.7461 -0.6419 0.1769 +vn -0.5761 -0.7467 0.3325 +vn -0.9657 0.2474 -0.0785 +vn -0.8784 0.4775 -0.0191 +vn -0.7429 0.6639 0.0856 +vn -0.0250 0.7056 0.7081 +vn -0.1950 0.8104 0.5524 +vn 0.1095 0.5349 0.8377 +vn -0.3836 0.8389 0.3861 +vn -0.5724 0.7885 0.2251 +vn -0.6396 0.2702 0.7196 +vn -0.5889 0.2626 0.7643 +vn -0.5957 0.4637 0.6558 +vn -0.6906 0.2565 0.6761 +vn -0.4989 0.4490 0.7412 +vn -0.5433 0.2344 0.8062 +vn -0.4116 0.3952 0.8212 +vn -0.6926 0.4378 0.5732 +vn -0.7729 0.1729 0.6105 +vn -0.7365 0.2231 0.6386 +vn -0.8498 0.2781 0.4478 +vn -0.7965 0.1108 0.5944 +vn -0.7801 0.3738 0.5016 +vn -0.4840 -0.0051 0.8750 +vn -0.2988 -0.0614 0.9523 +vn -0.2832 0.0675 0.9567 +vn -0.4758 0.0625 0.8773 +vn -0.3437 -0.1795 0.9218 +vn -0.5076 -0.0671 0.8589 +vn -0.4133 -0.2752 0.8680 +vn -0.4837 0.1291 0.8657 +vn -0.5068 0.1883 0.8412 +vn -0.3424 0.3076 0.8877 +vn -0.2983 0.1947 0.9344 +vn -0.8946 0.1599 0.4173 +vn -0.6560 0.0542 0.7528 +vn -0.8047 0.0434 0.5921 +vn -0.7968 -0.0232 0.6038 +vn -0.7736 -0.0825 0.6283 +vn -0.7373 -0.1285 0.6632 +vn -0.6916 -0.1567 0.7051 +vn -0.5440 -0.1172 0.8309 +vn -0.5898 -0.1507 0.7933 +vn -0.6408 -0.1644 0.7499 +vn -0.5008 -0.3392 0.7963 +f 1/1/1 2/2/2 3/3/3 +f 2/2/2 1/1/1 4/4/4 +f 4/4/4 5/5/5 2/2/2 +f 6/6/6 7/7/7 8/8/8 +f 8/8/8 3/3/3 6/6/6 +f 8/8/8 1/1/1 3/3/3 +f 9/9/9 10/10/10 11/11/11 +f 12/12/12 10/10/10 9/9/9 +f 13/13/13 12/12/12 9/9/9 +f 14/14/14 5/5/5 4/4/4 +f 11/11/11 14/14/14 4/4/4 +f 10/10/10 14/14/14 11/11/11 +f 15/15/15 16/16/16 17/17/17 +f 18/18/18 15/15/15 17/17/17 +f 19/19/19 18/18/18 17/17/17 +f 20/20/20 21/21/21 17/17/17 +f 22/22/22 20/20/20 17/17/17 +f 16/16/16 22/22/22 17/17/17 +f 23/23/23 24/24/24 25/25/25 +f 6/6/6 24/24/24 23/23/23 +f 7/7/7 6/6/6 23/23/23 +f 26/26/26 27/27/27 28/28/28 +f 28/28/28 29/29/29 26/26/26 +f 24/24/24 28/28/28 25/25/25 +f 30/30/30 31/31/31 32/32/32 +f 33/33/33 30/30/30 34/34/34 +f 35/35/35 33/33/33 34/34/34 +f 36/36/36 37/37/37 32/32/32 +f 32/32/32 31/31/31 36/36/36 +f 32/32/32 34/34/34 30/30/30 +f 38/38/38 27/27/27 39/39/39 +f 27/27/27 38/38/38 25/25/25 +f 25/25/25 28/28/28 27/27/27 +f 33/33/33 35/35/35 40/40/40 +f 40/40/40 39/39/39 33/33/33 +f 39/39/39 40/40/40 38/38/38 +f 41/41/41 42/42/42 43/43/43 +f 44/44/44 42/42/42 41/41/41 +f 45/45/45 44/44/44 41/41/41 +f 12/12/12 13/13/13 46/46/46 +f 46/46/46 43/43/43 12/12/12 +f 43/43/43 46/46/46 41/41/41 +f 47/47/47 48/48/48 49/49/49 +f 48/48/48 47/47/47 37/37/37 +f 37/37/37 36/36/36 48/48/48 +f 50/50/50 44/44/44 45/45/45 +f 49/49/49 50/50/50 45/45/45 +f 48/48/48 50/50/50 49/49/49 +f 51/51/51 52/52/52 53/53/53 +f 52/52/52 51/51/51 54/54/54 +f 55/55/55 53/53/53 26/26/26 +f 53/53/53 55/55/55 51/51/51 +f 56/56/56 57/57/57 54/54/54 +f 57/57/57 56/56/56 58/58/58 +f 51/51/51 59/59/59 54/54/54 +f 54/54/54 59/59/59 56/56/56 +f 60/60/60 61/61/61 24/24/24 +f 24/24/24 61/61/61 28/28/28 +f 60/60/60 6/6/6 3/3/3 +f 6/6/6 60/60/60 24/24/24 +f 62/62/62 63/63/63 26/26/26 +f 26/26/26 63/63/63 55/55/55 +f 61/61/61 29/29/29 28/28/28 +f 29/29/29 62/62/62 26/26/26 +f 56/56/56 64/64/64 58/58/58 +f 65/65/65 66/66/66 67/67/67 +f 67/67/67 68/68/68 65/65/65 +f 69/69/69 70/70/70 65/65/65 +f 70/70/70 66/66/66 65/65/65 +f 71/71/71 72/72/72 73/73/73 +f 72/72/72 74/74/74 73/73/73 +f 68/68/68 67/67/67 71/71/71 +f 67/67/67 72/72/72 71/71/71 +f 75/75/75 76/76/76 77/77/77 +f 76/76/76 78/78/78 77/77/77 +f 58/58/58 64/64/64 76/76/76 +f 76/76/76 75/75/75 58/58/58 +f 79/79/79 70/70/70 69/69/69 +f 79/79/79 80/80/80 70/70/70 +f 77/77/77 78/78/78 79/79/79 +f 78/78/78 80/80/80 79/79/79 +f 36/36/36 58/58/58 75/75/75 +f 75/75/75 48/48/48 36/36/36 +f 31/31/31 57/57/57 58/58/58 +f 58/58/58 36/36/36 31/31/31 +f 50/50/50 77/77/77 44/44/44 +f 77/77/77 79/79/79 44/44/44 +f 48/48/48 75/75/75 50/50/50 +f 75/75/75 77/77/77 50/50/50 +f 39/39/39 53/53/53 52/52/52 +f 52/52/52 33/33/33 39/39/39 +f 27/27/27 26/26/26 53/53/53 +f 53/53/53 39/39/39 27/27/27 +f 30/30/30 54/54/54 31/31/31 +f 54/54/54 57/57/57 31/31/31 +f 33/33/33 52/52/52 30/30/30 +f 52/52/52 54/54/54 30/30/30 +f 44/44/44 79/79/79 42/42/42 +f 73/73/73 81/81/81 5/5/5 +f 5/5/5 82/82/82 2/2/2 +f 71/71/71 73/73/73 14/14/14 +f 14/14/14 73/73/73 5/5/5 +f 83/83/83 3/3/3 2/2/2 +f 3/3/3 83/83/83 60/60/60 +f 5/5/5 81/81/81 82/82/82 +f 2/2/2 82/82/82 83/83/83 +f 65/65/65 43/43/43 42/42/42 +f 43/43/43 65/65/65 68/68/68 +f 79/79/79 69/69/69 42/42/42 +f 42/42/42 69/69/69 65/65/65 +f 68/68/68 71/71/71 10/10/10 +f 10/10/10 71/71/71 14/14/14 +f 68/68/68 12/12/12 43/43/43 +f 12/12/12 68/68/68 10/10/10 +f 22/22/22 84/84/84 85/85/85 +f 84/84/84 22/22/22 86/86/86 +f 21/21/21 20/20/20 85/85/85 +f 85/85/85 20/20/20 22/22/22 +f 16/16/16 15/15/15 87/87/87 +f 87/87/87 15/15/15 18/18/18 +f 22/22/22 16/16/16 86/86/86 +f 86/86/86 16/16/16 87/87/87 +f 88/88/88 89/89/89 67/67/67 +f 67/67/67 89/89/89 90/90/90 +f 88/88/88 66/66/66 70/70/70 +f 66/66/66 88/88/88 67/67/67 +f 21/21/21 74/74/74 72/72/72 +f 74/74/74 21/21/21 85/85/85 +f 90/90/90 72/72/72 67/67/67 +f 72/72/72 90/90/90 21/21/21 +f 18/18/18 91/91/91 87/87/87 +f 92/92/92 93/93/93 17/17/17 +f 94/94/94 92/92/92 17/17/17 +f 95/95/95 96/96/96 17/17/17 +f 93/93/93 95/95/95 17/17/17 +f 90/90/90 89/89/89 17/17/17 +f 21/21/21 90/90/90 17/17/17 +f 88/88/88 94/94/94 17/17/17 +f 89/89/89 88/88/88 17/17/17 +f 97/97/97 19/19/19 17/17/17 +f 98/98/98 97/97/97 17/17/17 +f 91/91/91 18/18/18 62/62/62 +f 18/18/18 19/19/19 62/62/62 +f 99/99/99 100/100/100 17/17/17 +f 96/96/96 99/99/99 17/17/17 +f 101/101/101 98/98/98 17/17/17 +f 100/100/100 101/101/101 17/17/17 +f 61/61/61 91/91/91 62/62/62 +f 62/62/62 29/29/29 61/61/61 +f 60/60/60 87/87/87 61/61/61 +f 87/87/87 91/91/91 61/61/61 +f 63/63/63 97/97/97 55/55/55 +f 97/97/97 98/98/98 55/55/55 +f 62/62/62 19/19/19 97/97/97 +f 97/97/97 63/63/63 62/62/62 +f 81/81/81 85/85/85 82/82/82 +f 85/85/85 84/84/84 82/82/82 +f 73/73/73 74/74/74 85/85/85 +f 85/85/85 81/81/81 73/73/73 +f 83/83/83 86/86/86 87/87/87 +f 87/87/87 60/60/60 83/83/83 +f 82/82/82 84/84/84 86/86/86 +f 86/86/86 83/83/83 82/82/82 +f 55/55/55 98/98/98 51/51/51 +f 93/93/93 78/78/78 76/76/76 +f 78/78/78 93/93/93 92/92/92 +f 96/96/96 95/95/95 76/76/76 +f 76/76/76 95/95/95 93/93/93 +f 92/92/92 94/94/94 70/70/70 +f 70/70/70 94/94/94 88/88/88 +f 92/92/92 80/80/80 78/78/78 +f 80/80/80 92/92/92 70/70/70 +f 100/100/100 59/59/59 51/51/51 +f 100/100/100 99/99/99 56/56/56 +f 98/98/98 101/101/101 51/51/51 +f 51/51/51 101/101/101 100/100/100 +f 96/96/96 64/64/64 56/56/56 +f 64/64/64 96/96/96 76/76/76 +f 56/56/56 59/59/59 100/100/100 +f 56/56/56 99/99/99 96/96/96 +f 102/102/102 103/103/103 104/104/104 +f 102/102/102 104/104/104 105/105/105 +f 103/103/103 106/106/106 104/104/104 +f 107/107/107 108/108/108 106/106/106 +f 103/103/103 107/107/107 106/106/106 +f 109/109/109 105/105/105 104/104/104 +f 110/110/110 111/111/111 112/112/112 +f 110/110/110 112/112/112 113/113/113 +f 111/111/111 114/114/114 112/112/112 +f 105/105/105 109/109/109 111/111/111 +f 114/114/114 111/111/111 109/109/109 +f 115/115/115 116/116/116 117/117/117 +f 118/118/118 115/115/115 117/117/117 +f 115/115/115 119/119/119 116/116/116 +f 120/120/120 119/119/119 121/121/121 +f 119/119/119 120/120/120 116/116/116 +f 118/118/118 117/117/117 122/122/122 +f 123/123/123 124/124/124 108/108/108 +f 107/107/107 123/123/123 108/108/108 +f 124/124/124 123/123/123 125/125/125 +f 125/125/125 122/122/122 117/117/117 +f 122/122/122 125/125/125 123/123/123 +f 126/126/126 110/110/110 113/113/113 +f 127/127/127 128/128/128 129/129/129 +f 130/130/130 129/129/129 128/128/128 +f 127/127/127 131/131/131 128/128/128 +f 132/132/132 133/133/133 134/134/134 +f 131/131/131 132/132/132 128/128/128 +f 129/129/129 130/130/130 135/135/135 +f 136/136/136 115/115/115 137/137/137 +f 118/118/118 137/137/137 115/115/115 +f 136/136/136 135/135/135 115/115/115 +f 119/119/119 135/135/135 130/130/130 +f 135/135/135 119/119/119 115/115/115 +f 138/138/138 139/139/139 140/140/140 +f 140/140/140 141/141/141 142/142/142 +f 140/140/140 139/139/139 141/141/141 +f 126/126/126 113/113/113 139/139/139 +f 138/138/138 126/126/126 139/139/139 +f 143/143/143 142/142/142 141/141/141 +f 133/133/133 144/144/144 145/145/145 +f 133/133/133 145/145/145 134/134/134 +f 144/144/144 146/146/146 145/145/145 +f 142/142/142 143/143/143 144/144/144 +f 146/146/146 144/144/144 143/143/143 +f 124/124/124 147/147/147 148/148/148 +f 108/108/108 124/124/124 148/148/148 +f 147/147/147 124/124/124 149/149/149 +f 149/149/149 125/125/125 150/150/150 +f 125/125/125 149/149/149 124/124/124 +f 108/108/108 148/148/148 151/151/151 +f 104/104/104 152/152/152 109/109/109 +f 153/153/153 109/109/109 152/152/152 +f 104/104/104 106/106/106 152/152/152 +f 106/106/106 108/108/108 151/151/151 +f 106/106/106 151/151/151 152/152/152 +f 154/154/154 121/121/121 155/155/155 +f 121/121/121 154/154/154 120/120/120 +f 156/156/156 155/155/155 121/121/121 +f 134/134/134 157/157/157 156/156/156 +f 155/155/155 156/156/156 157/157/157 +f 158/158/158 120/120/120 154/154/154 +f 159/159/159 150/150/150 116/116/116 +f 117/117/117 150/150/150 125/125/125 +f 117/117/117 116/116/116 150/150/150 +f 120/120/120 158/158/158 159/159/159 +f 116/116/116 120/120/120 159/159/159 +f 109/109/109 153/153/153 114/114/114 +f 145/145/145 146/146/146 160/160/160 +f 145/145/145 160/160/160 157/157/157 +f 146/146/146 161/161/161 160/160/160 +f 143/143/143 162/162/162 146/146/146 +f 161/161/161 146/146/146 162/162/162 +f 134/134/134 145/145/145 157/157/157 +f 121/121/121 130/130/130 156/156/156 +f 130/130/130 121/121/121 119/119/119 +f 128/128/128 156/156/156 130/130/130 +f 132/132/132 134/134/134 128/128/128 +f 156/156/156 128/128/128 134/134/134 +f 112/112/112 163/163/163 164/164/164 +f 113/113/113 112/112/112 164/164/164 +f 112/112/112 114/114/114 163/163/163 +f 165/165/165 114/114/114 153/153/153 +f 114/114/114 165/165/165 163/163/163 +f 113/113/113 164/164/164 166/166/166 +f 141/141/141 167/167/167 143/143/143 +f 162/162/162 143/143/143 167/167/167 +f 167/167/167 141/141/141 166/166/166 +f 139/139/139 113/113/113 166/166/166 +f 139/139/139 166/166/166 141/141/141 +f 168/168/168 169/169/169 170/170/170 +f 168/168/168 170/170/170 171/171/171 +f 169/169/169 172/172/172 170/170/170 +f 173/173/173 174/174/174 169/169/169 +f 172/172/172 169/169/169 174/174/174 +f 175/175/175 171/171/171 170/170/170 +f 176/176/176 177/177/177 178/178/178 +f 176/176/176 178/178/178 179/179/179 +f 177/177/177 180/180/180 178/178/178 +f 171/171/171 175/175/175 180/180/180 +f 177/177/177 171/171/171 180/180/180 +f 181/181/181 182/182/182 183/183/183 +f 184/184/184 181/181/181 183/183/183 +f 182/182/182 181/181/181 185/185/185 +f 185/185/185 186/186/186 187/187/187 +f 186/186/186 185/185/185 181/181/181 +f 184/184/184 183/183/183 188/188/188 +f 189/189/189 190/190/190 173/173/173 +f 174/174/174 173/173/173 190/190/190 +f 189/189/189 188/188/188 190/190/190 +f 191/191/191 188/188/188 183/183/183 +f 188/188/188 191/191/191 190/190/190 +f 192/192/192 179/179/179 178/178/178 +f 189/189/189 173/173/173 193/193/193 +f 173/173/173 169/169/169 193/193/193 +f 188/188/188 189/189/189 193/193/193 +f 181/181/181 184/184/184 193/193/193 +f 184/184/184 188/188/188 193/193/193 +f 169/169/169 168/168/168 193/193/193 +f 176/176/176 179/179/179 193/193/193 +f 179/179/179 194/194/194 193/193/193 +f 177/177/177 176/176/176 193/193/193 +f 168/168/168 171/171/171 193/193/193 +f 171/171/171 177/177/177 193/193/193 +f 195/195/195 196/196/196 193/193/193 +f 196/196/196 197/197/197 193/193/193 +f 194/194/194 195/195/195 193/193/193 +f 179/179/179 192/192/192 131/131/131 +f 194/194/194 179/179/179 131/131/131 +f 197/197/197 198/198/198 193/193/193 +f 199/199/199 186/186/186 193/193/193 +f 186/186/186 181/181/181 193/193/193 +f 200/200/200 199/199/199 193/193/193 +f 198/198/198 201/201/201 193/193/193 +f 201/201/201 200/200/200 193/193/193 +f 190/190/190 111/111/111 110/110/110 +f 174/174/174 190/190/190 110/110/110 +f 111/111/111 190/190/190 105/105/105 +f 191/191/191 183/183/183 105/105/105 +f 191/191/191 105/105/105 190/190/190 +f 174/174/174 110/110/110 126/126/126 +f 170/170/170 138/138/138 140/140/140 +f 175/175/175 170/170/170 140/140/140 +f 138/138/138 170/170/170 126/126/126 +f 172/172/172 174/174/174 126/126/126 +f 172/172/172 126/126/126 170/170/170 +f 123/123/123 187/187/187 122/122/122 +f 187/187/187 123/123/123 107/107/107 +f 202/202/202 122/122/122 187/187/187 +f 137/137/137 118/118/118 122/122/122 +f 202/202/202 137/137/137 122/122/122 +f 185/185/185 187/187/187 107/107/107 +f 182/182/182 103/103/103 183/183/183 +f 183/183/183 102/102/102 105/105/105 +f 183/183/183 103/103/103 102/102/102 +f 185/185/185 107/107/107 103/103/103 +f 182/182/182 185/185/185 103/103/103 +f 175/175/175 140/140/140 180/180/180 +f 136/136/136 198/198/198 135/135/135 +f 201/201/201 198/198/198 137/137/137 +f 197/197/197 135/135/135 198/198/198 +f 196/196/196 129/129/129 135/135/135 +f 197/197/197 196/196/196 135/135/135 +f 136/136/136 137/137/137 198/198/198 +f 199/199/199 200/200/200 187/187/187 +f 199/199/199 187/187/187 186/186/186 +f 200/200/200 202/202/202 187/187/187 +f 201/201/201 137/137/137 200/200/200 +f 202/202/202 200/200/200 137/137/137 +f 178/178/178 144/144/144 133/133/133 +f 192/192/192 178/178/178 133/133/133 +f 144/144/144 178/178/178 142/142/142 +f 142/142/142 180/180/180 140/140/140 +f 180/180/180 142/142/142 178/178/178 +f 192/192/192 133/133/133 131/131/131 +f 195/195/195 127/127/127 129/129/129 +f 196/196/196 195/195/195 129/129/129 +f 127/127/127 195/195/195 131/131/131 +f 132/132/132 131/131/131 133/133/133 +f 194/194/194 131/131/131 195/195/195 +v 0.688634 0.501236 0.200234 +v 0.668460 0.559692 0.176404 +v 0.694361 0.523166 0.238133 +v 0.677681 0.580793 0.212475 +v 0.662370 0.532657 0.143786 +v 0.648507 0.623694 0.186300 +v 0.699266 0.550846 0.272572 +v 0.670789 0.670644 0.235268 +v 0.686460 0.606253 0.245304 +v 0.685220 0.488121 0.157681 +v 0.632487 0.673871 0.175641 +v 0.610171 0.734188 0.190536 +v 0.644426 0.728023 0.229496 +v 0.606162 0.705766 0.164607 +v 0.642620 0.592226 0.120005 +v 0.610777 0.766583 0.221271 +v 0.686877 0.668938 0.301330 +v 0.690843 0.635740 0.274926 +v 0.678473 0.702279 0.325073 +v 0.670803 0.710477 0.275139 +v 0.667177 0.735006 0.299631 +v 0.643061 0.749635 0.254416 +v 0.640571 0.779166 0.278920 +v 0.693545 0.625995 0.327591 +v 0.682866 0.668182 0.348150 +v 0.700082 0.584918 0.302672 +v 0.602730 0.679226 0.136156 +v 0.557938 0.763425 0.179428 +v 0.552766 0.806221 0.216755 +v 0.577503 0.782889 0.206107 +v 0.531272 0.741263 0.155231 +v 0.500959 0.769841 0.177683 +v 0.583559 0.753412 0.183090 +v 0.580994 0.725044 0.158669 +v 0.500959 0.727816 0.143670 +v 0.551370 0.547939 0.439991 +v 0.571996 0.519115 0.428097 +v 0.598142 0.562633 0.409059 +v 0.647921 0.567478 0.390433 +v 0.626972 0.497066 0.403194 +v 0.590148 0.597824 0.409146 +v 0.532071 0.809866 0.215165 +v 0.500959 0.823194 0.225416 +v 0.500959 0.719305 0.688316 +v 0.500959 0.676331 0.680001 +v 0.543571 0.705405 0.682665 +v 0.554944 0.709072 0.130578 +v 0.530606 0.715022 0.130572 +v 0.621197 0.619872 0.068976 +v 0.599488 0.646020 0.065866 +v 0.577524 0.676468 0.101079 +v 0.500959 0.673098 0.050282 +v 0.500959 0.692590 0.102995 +v 0.530085 0.693110 0.102115 +v 0.657593 0.711868 0.387707 +v 0.650524 0.729935 0.402945 +v 0.645705 0.711159 0.403085 +v 0.642307 0.674393 0.396820 +v 0.665297 0.614071 0.379279 +v 0.667185 0.677767 0.376943 +v 0.621070 0.699067 0.437283 +v 0.635049 0.692856 0.408601 +v 0.669539 0.732202 0.346705 +v 0.637351 0.720835 0.428363 +v 0.631336 0.719152 0.446891 +v 0.641148 0.734438 0.437389 +v 0.671261 0.705588 0.365163 +v 0.628660 0.657994 0.401794 +v 0.596977 0.624244 0.406464 +v 0.646165 0.626225 0.391773 +v 0.650890 0.511084 0.389312 +v 0.672440 0.545726 0.371350 +v 0.597442 0.639432 0.409383 +v 0.576342 0.654452 0.025856 +v 0.552662 0.655534 -0.013169 +v 0.529419 0.668863 0.029958 +v 0.553308 0.673317 0.066216 +v 0.552551 0.645827 -0.055893 +v 0.529131 0.651159 -0.047245 +v 0.500959 0.660550 -0.007653 +v 0.529699 0.678824 0.068005 +v 0.500959 0.646011 -0.060985 +v 0.647064 0.813190 0.419322 +v 0.649464 0.772879 0.427272 +v 0.657903 0.773937 0.373194 +v 0.687695 0.584468 0.350867 +v 0.695924 0.537320 0.330916 +v 0.663402 0.758766 0.324642 +v 0.678063 0.632695 0.365273 +v 0.681256 0.493680 0.357824 +v 0.624715 0.777865 0.245260 +v 0.652606 0.750672 0.405428 +v 0.658966 0.454585 0.381782 +v 0.626014 0.430596 0.405949 +v 1.028065 -0.028822 0.036488 +v 1.031677 -0.027256 0.050523 +v 1.029736 -0.028638 0.044417 +v 1.013930 -0.000455 0.012509 +v 0.993817 0.039208 -0.007447 +v 1.016020 0.004271 0.013013 +v 1.002534 0.012276 0.009291 +v 0.994907 0.026470 0.001472 +v 1.029919 -0.026848 0.035993 +v 1.025936 -0.027362 0.028465 +v 1.023716 -0.023392 0.023353 +v 1.028203 -0.024766 0.028007 +v 1.022458 -0.026258 0.034935 +v 1.022389 -0.025511 0.048231 +v 0.526832 0.855288 0.612069 +v 0.554526 0.837975 0.609469 +v 0.543309 0.846764 0.608747 +v 0.555086 0.844310 0.598316 +v 0.551100 0.852811 0.587916 +v 0.510590 0.842317 0.633935 +v 0.544606 0.828857 0.635023 +v 1.020685 0.003655 0.026927 +v 1.008876 0.018583 0.008055 +v 1.023764 -0.013473 0.019867 +v 0.591168 0.221597 -1.254470 +v 0.634591 0.203091 -1.315050 +v 0.619537 0.180125 -1.293590 +v 0.575016 0.205314 -1.239180 +v 0.637468 0.140379 -1.306700 +v 0.668524 0.175087 -1.354480 +v 0.566115 0.155306 -1.241880 +v 0.562030 0.181028 -1.237360 +v 0.500959 0.202557 -1.177050 +v 0.532825 0.214628 -1.183750 +v 0.543339 0.230331 -1.184290 +v 0.698027 0.151006 -1.384740 +v 1.029178 -0.019200 0.033938 +v 1.026221 -0.020103 0.023091 +v 1.024730 -0.007459 0.025607 +v 0.542302 0.856474 0.587046 +v 0.577026 0.874849 0.564659 +v 0.562472 0.883759 0.545254 +v 0.546248 0.864357 0.567246 +v 0.580683 0.880287 0.554143 +v 0.565161 0.844871 0.588505 +v 0.565223 0.850776 0.584834 +v 0.558020 0.848361 0.590624 +v 0.573192 0.867143 0.573768 +v 0.567917 0.916119 0.464188 +v 0.558404 0.923740 0.437056 +v 0.535730 0.920970 0.473392 +v 0.553423 0.913879 0.485951 +v 0.567327 0.909953 0.485149 +v 0.581428 0.865570 0.568831 +v 0.581662 0.869117 0.570583 +v 0.575078 0.859459 0.579210 +v 0.569764 0.860735 0.579794 +v 0.566000 0.855952 0.582075 +v 0.531487 0.880189 0.550502 +v 0.523004 0.894433 0.536944 +v 0.525858 0.881787 0.549029 +v 0.536022 0.864632 0.567497 +v 0.526970 0.872380 0.561206 +v 0.517657 0.877070 0.560208 +v 0.512824 0.893524 0.542171 +v 0.500959 0.919158 0.488506 +v 0.500959 0.901999 0.531257 +v 0.534587 0.907407 0.514522 +v 0.532121 0.896206 0.532757 +v 0.546678 0.904902 0.519684 +v 0.608023 0.876964 0.457550 +v 0.633101 0.845261 0.439745 +v 0.610285 0.892979 0.422739 +v 0.582472 0.911205 0.460406 +v 0.594259 0.908739 0.430808 +v 0.715237 0.058821 -1.325120 +v 0.674875 0.101718 -1.265780 +v 0.672509 0.095834 -1.262240 +v 0.706847 0.056073 -1.314110 +v 0.671013 0.106237 -1.264430 +v 0.641699 0.132379 -1.198970 +v 0.637004 0.124348 -1.194620 +v 0.635679 0.144346 -1.203570 +v 0.654528 0.127964 -1.261980 +v 0.740630 0.042107 -1.364790 +v 0.705692 0.079544 -1.332450 +v 0.749423 0.031761 -1.371220 +v 0.754743 0.058292 -1.412730 +v 0.660268 0.091532 -1.252910 +v 0.618902 0.174419 -1.205400 +v 0.530467 0.633329 0.616538 +v 0.535867 0.646658 0.611794 +v 0.528399 0.645271 0.619911 +v 0.542349 0.644569 0.606316 +v 0.530436 0.622635 0.609007 +v 0.519780 0.626398 0.616568 +v 0.514533 0.619256 0.610354 +v 0.582226 0.621158 0.415400 +v 0.525317 0.617291 0.603621 +v 0.500959 0.614693 0.602244 +v 0.500959 0.628915 0.621124 +v 0.500959 0.646902 0.628256 +v 0.515142 0.646610 0.627454 +v 0.539450 0.626716 0.603790 +v 0.721017 0.030116 -1.350760 +v 0.713878 0.032509 -1.338010 +v 0.654562 0.061682 -1.288660 +v 0.612029 0.088463 -1.228880 +v 0.558266 0.242684 -1.193470 +v 0.736998 0.025631 -1.355470 +v 0.691635 0.055055 -1.304740 +v 0.770333 0.008718 -1.395930 +v 0.646646 0.194704 -1.323480 +v 0.603222 0.222366 -1.259520 +v 0.570275 0.247777 -1.200070 +v 0.639271 0.091015 -1.239520 +v 0.622120 0.117071 -1.186240 +v 0.595339 0.111225 -1.176520 +v 0.579948 0.095588 -1.228470 +v 0.562403 0.110026 -1.168370 +v 0.500959 0.117295 -1.161370 +v 0.616589 0.696836 0.474545 +v 0.604851 0.683557 0.480779 +v 0.606660 0.687594 0.468165 +v 0.610433 0.691248 0.456331 +v 0.590462 0.673160 0.487305 +v 0.606715 0.684627 0.450204 +v 0.626316 0.722931 0.499593 +v 0.623409 0.707404 0.485958 +v 0.635355 0.746019 0.482765 +v 0.637227 0.770833 0.483735 +v 0.624730 0.741230 0.511800 +v 0.620293 0.701474 0.499688 +v 0.588426 0.647184 0.424975 +v 0.615966 0.670834 0.415311 +v 0.626898 0.805028 0.489048 +v 0.627882 0.785050 0.501029 +v 0.640588 0.802033 0.457857 +v 0.622118 0.837858 0.484492 +v 0.637359 0.852603 0.413964 +v 0.549637 0.585078 0.443153 +v 0.525013 0.561451 0.457477 +v 0.534044 0.466177 0.448708 +v 0.526334 0.583887 0.462473 +v 0.547150 0.599294 0.451822 +v 0.549755 0.608863 0.459715 +v 0.500959 0.571570 0.464207 +v 0.569094 0.372703 0.427105 +v 0.598833 0.394058 0.417628 +v 0.531731 0.428115 0.445782 +v 0.537971 0.358626 0.432701 +v 0.500959 0.441982 0.452372 +v 0.585954 0.666200 0.476135 +v 0.553694 0.621327 0.474042 +v 0.530469 0.601755 0.475099 +v 0.500959 0.594023 0.475997 +v 0.565799 0.620678 0.439879 +v 0.556252 0.827116 0.630153 +v 0.569446 0.826824 0.614558 +v 0.568360 0.820700 0.635800 +v 0.581990 0.821482 0.609257 +v 0.580518 0.818178 0.627616 +v 0.510624 0.833647 0.646428 +v 0.542445 0.822898 0.647488 +v 0.574956 0.813182 0.640316 +v 0.576332 0.828011 0.587678 +v 0.543798 0.883801 0.546303 +v 0.563675 0.836801 0.596703 +v 0.500959 0.929365 0.439054 +v 0.529233 0.615378 -0.148421 +v 0.527982 0.587551 -0.226392 +v 0.500959 0.612995 -0.145210 +v 0.500959 0.825970 0.658179 +v 0.500959 0.857733 0.612309 +v 0.500959 0.879153 0.559282 +v 0.574448 0.887689 0.528008 +v 0.572976 0.895093 0.504646 +v 0.567767 0.895833 0.516652 +v 0.578961 0.905367 0.480873 +v 0.555250 0.890614 0.536255 +v 0.597733 0.866787 0.508792 +v 0.615508 0.854841 0.483344 +v 0.607551 0.836710 0.514872 +v 0.605246 0.795599 0.537784 +v 0.609522 0.850004 0.513888 +v 0.571419 0.920352 0.428670 +v 0.563247 0.903479 0.508477 +v 0.682925 0.499440 0.077679 +v 0.735747 0.443203 0.021558 +v 0.671579 0.529268 0.022292 +v 0.718833 0.429729 0.102893 +v 0.767287 0.357587 0.060284 +v 0.704676 0.506614 -0.052610 +v 0.751407 0.357198 0.138068 +v 0.715141 0.416705 0.189794 +v 0.677938 0.549850 -0.068618 +v 0.648625 0.584224 -0.022874 +v 0.645026 0.583679 0.027094 +v 0.642232 0.585198 0.075460 +v 0.721964 0.229895 0.316423 +v 0.757372 0.184639 0.280678 +v 0.754806 0.266209 0.256752 +v 0.775206 0.218492 0.242896 +v 0.801382 0.208065 0.194591 +v 0.734904 0.290673 0.292729 +v 0.729811 0.360164 0.263236 +v 0.714064 0.396374 0.299261 +v 0.709104 0.336066 0.327126 +v 0.690733 0.283910 0.349907 +v 0.741785 0.340041 0.224807 +v 0.770382 0.291480 0.178372 +v 0.789638 0.264465 0.153095 +v 0.831296 0.230390 0.075720 +v 0.774375 0.304855 0.111105 +v 0.651854 0.582058 -0.071430 +v 0.576715 0.663118 0.065216 +v 0.576209 0.647258 -0.016064 +v 0.599570 0.638852 0.024721 +v 0.600011 0.633451 -0.019058 +v 0.576239 0.638481 -0.059939 +v 0.600561 0.626139 -0.064320 +v 0.622426 0.615149 0.024562 +v 0.624217 0.612400 -0.022098 +v 0.625914 0.607367 -0.069014 +v 0.625749 0.318415 0.395522 +v 0.657202 0.351238 0.380730 +v 0.588808 0.294990 0.404682 +v 0.572643 0.131033 0.342192 +v 0.580161 0.070379 0.303683 +v 0.647730 0.094418 0.303820 +v 0.500959 0.125067 0.342546 +v 0.500959 0.062612 0.302159 +v 0.633834 0.150559 0.338799 +v 0.656745 0.244975 0.364909 +v 0.685941 0.184096 0.330622 +v 0.611864 0.218512 0.373757 +v 0.500959 0.276273 0.410968 +v 0.548462 0.280949 0.409583 +v 0.500959 0.353403 0.434538 +v 0.560815 0.203776 0.378072 +v 0.500959 0.199342 0.379093 +v 0.711736 0.432497 0.230851 +v 0.681081 0.393474 0.358932 +v 0.696504 0.442387 0.332292 +v 0.707819 0.460174 0.268392 +v 0.702590 0.495500 0.302588 +v 0.704208 0.135856 0.297941 +v 0.586196 0.871845 0.563035 +v 0.569171 0.643672 0.579752 +v 0.579556 0.639509 0.566166 +v 0.592708 0.657077 0.573150 +v 0.585596 0.652152 0.593939 +v 0.558296 0.646077 0.593129 +v 0.596317 0.657078 0.559205 +v 0.579183 0.664070 0.500481 +v 0.603756 0.672062 0.518929 +v 0.598899 0.661004 0.531148 +v 0.604949 0.668669 0.537240 +v 0.591412 0.671313 0.498831 +v 0.584790 0.647810 0.604270 +v 0.554747 0.644216 0.653538 +v 0.572017 0.640209 0.640469 +v 0.581572 0.640511 0.624027 +v 0.615165 0.690621 0.489434 +v 0.611793 0.685746 0.503521 +v 0.605895 0.681139 0.491830 +v 0.581360 0.642241 0.552658 +v 0.599140 0.657870 0.541576 +v 0.581180 0.649273 0.530996 +v 0.581244 0.666419 0.489475 +v 0.539566 0.654879 0.665402 +v 0.553067 0.788875 0.667964 +v 0.545339 0.794874 0.668868 +v 0.551210 0.790437 0.670699 +v 0.553117 0.786291 0.675699 +v 0.550162 0.785546 0.679611 +v 0.536850 0.800824 0.668946 +v 0.527313 0.800115 0.676258 +v 0.547628 0.795278 0.662622 +v 0.514099 0.775988 0.696147 +v 0.525263 0.760291 0.698989 +v 0.533860 0.766707 0.695891 +v 0.546782 0.777113 0.688024 +v 0.530994 0.784508 0.687531 +v 0.541111 0.772748 0.692093 +v 0.535227 0.795020 0.676064 +v 0.554523 0.785466 0.672168 +v 0.553750 0.781498 0.679623 +v 0.554900 0.781183 0.675530 +v 0.514235 0.798064 0.685637 +v 0.500959 0.786694 0.693185 +v 0.500959 0.761710 0.700684 +v 0.500959 0.797077 0.688041 +v 0.527289 0.663128 0.672820 +v 0.500959 0.744664 0.700513 +v 0.515592 0.754873 0.701007 +v 0.606047 0.683798 0.570210 +v 0.602287 0.668671 0.550972 +v 0.557059 0.670800 0.669618 +v 0.571193 0.665814 0.661613 +v 0.581906 0.683300 0.664877 +v 0.566939 0.685148 0.672401 +v 0.626627 0.888216 0.340726 +v 0.620597 0.893734 0.340280 +v 0.625965 0.891315 0.346821 +v 0.613479 0.895185 0.344574 +v 0.618126 0.897533 0.345906 +v 0.606944 0.898533 0.344743 +v 0.580600 0.663481 0.653196 +v 0.591483 0.683112 0.656408 +v 0.591521 0.662534 0.634190 +v 0.601265 0.672017 0.601692 +v 0.611133 0.698299 0.606768 +v 0.603647 0.682840 0.623260 +v 0.601480 0.683758 0.635974 +v 0.597467 0.683590 0.646857 +v 0.622248 0.829489 0.281685 +v 0.624740 0.802202 0.262298 +v 0.603712 0.822405 0.263633 +v 0.611604 0.797542 0.241193 +v 0.591796 0.805541 0.233751 +v 0.608007 0.863550 0.304554 +v 0.631042 0.843568 0.308472 +v 0.635710 0.816014 0.290448 +v 0.625159 0.873365 0.319768 +v 0.634073 0.863179 0.322904 +v 0.588546 0.893863 0.347633 +v 0.615520 0.888308 0.335356 +v 0.588534 0.887470 0.325737 +v 0.623281 0.889390 0.337053 +v 0.618531 0.893241 0.338626 +v 0.569429 0.836503 0.254958 +v 0.578321 0.857041 0.286978 +v 0.617273 0.701743 0.513483 +v 0.615358 0.714573 0.526956 +v 0.610906 0.686146 0.525432 +v 0.609184 0.694070 0.548934 +v 0.613035 0.705454 0.585914 +v 0.611855 0.712161 0.564874 +v 0.595029 0.664441 0.586828 +v 0.426596 0.107386 -1.234000 +v 0.421970 0.095588 -1.228470 +v 0.290901 0.051430 -1.354990 +v 0.347356 0.061682 -1.288660 +v 0.500959 0.129284 -1.189620 +v 0.736553 0.447854 -0.056684 +v 0.774258 0.361262 -0.097142 +v 0.742078 0.430617 -0.122691 +v 0.561834 0.018629 -0.375238 +v 0.500959 0.006239 -0.194094 +v 0.500959 0.014074 -0.511824 +v 0.547542 0.405265 -0.684268 +v 0.541912 0.361342 -0.829636 +v 0.500959 0.381327 -0.795767 +v 0.709986 0.499696 -0.096210 +v 0.435803 0.155306 -1.241880 +v 0.431959 0.128237 -1.241200 +v 0.364450 0.140379 -1.306700 +v 0.293389 0.087978 -1.370930 +v 0.500959 0.169852 -1.201290 +v 0.500959 0.148721 -1.200000 +v 0.645638 0.316935 -0.654736 +v 0.654914 0.233473 -0.822363 +v 0.613842 0.288941 -0.845986 +v 0.674776 0.135663 -0.733262 +v 0.627670 0.097594 -0.929001 +v 0.667076 0.178443 -0.793621 +v 0.640141 0.158908 -0.965177 +v 0.623007 0.215767 -0.983395 +v 0.522744 0.811211 0.670668 +v 0.673080 0.085114 -0.561076 +v 0.621892 0.070306 -0.754434 +v 0.624428 0.120876 -1.041260 +v 0.632309 0.155560 -1.055380 +v 0.500959 0.429282 -0.655361 +v 0.500959 0.469291 -0.548274 +v 0.556136 0.458570 -0.540649 +v 0.550621 0.512050 -0.425986 +v 0.573058 0.334294 -0.851999 +v 0.575878 0.282727 -1.007290 +v 0.595272 0.366988 -0.687265 +v 0.403524 0.214533 -1.206790 +v 0.368403 0.177227 -1.273020 +v 0.383016 0.174419 -1.205400 +v 0.296226 0.079544 -1.332450 +v 0.347390 0.127964 -1.261980 +v 0.326598 0.159954 -1.344940 +v 0.247175 0.058292 -1.412730 +v 0.261288 0.042107 -1.364790 +v 0.266184 0.096914 -1.406870 +v 0.303891 0.151006 -1.384740 +v 0.355272 0.194704 -1.323480 +v 0.377490 0.120876 -1.041260 +v 0.374014 0.137690 -1.098860 +v 0.381539 0.124431 -1.093750 +v 0.369609 0.155560 -1.055380 +v 0.382197 0.169622 -1.109950 +v 0.431643 0.247777 -1.200070 +v 0.398696 0.222366 -1.259520 +v 0.418113 0.236769 -1.203360 +v 0.238371 0.031893 -1.405760 +v 0.231585 0.008718 -1.395930 +v 0.280901 0.030116 -1.350760 +v 0.439888 0.181028 -1.237360 +v 0.382381 0.180125 -1.293590 +v 0.252495 0.031761 -1.371220 +v 0.533380 0.762758 0.694788 +v 0.514348 0.756700 0.691463 +v 0.516530 0.751626 0.695725 +v 0.511722 0.747013 0.692986 +v 0.540212 0.769607 0.692429 +v 0.516573 0.760788 0.687626 +v 0.535093 0.769087 0.687834 +v 0.508411 0.735803 0.692192 +v 0.500959 0.733642 0.697978 +v 0.500959 0.727757 0.694506 +v 0.514527 0.751469 0.686990 +v 0.542342 0.769081 0.681210 +v 0.549572 0.775454 0.684632 +v 0.542818 0.770882 0.687157 +v 0.549199 0.772233 0.679382 +v 0.550777 0.770479 0.671603 +v 0.552307 0.776705 0.680478 +v 0.546574 0.767573 0.673794 +v 0.517932 0.762112 0.678942 +v 0.549234 0.767505 0.666335 +v 0.551648 0.771618 0.668907 +v 0.551689 0.773819 0.661913 +v 0.514646 0.743301 0.683944 +v 0.516133 0.755355 0.681493 +v 0.552962 0.778924 0.666079 +v 0.526525 0.764191 0.673428 +v 0.552062 0.785617 0.660033 +v 0.509982 0.728898 0.690558 +v 0.516819 0.722971 0.686030 +v 0.567990 0.838564 0.587199 +v 0.605414 0.811799 0.520603 +v 0.603962 0.827246 0.525154 +v 0.576114 0.844084 0.559554 +v 0.574413 0.849637 0.563428 +v 0.577592 0.843243 0.573824 +v 0.603543 0.823134 0.532214 +v 0.599132 0.816423 0.543682 +v 0.594476 0.820713 0.559667 +v 0.595358 0.812052 0.569266 +v 0.592378 0.813531 0.577899 +v 0.601284 0.800118 0.571778 +v 0.590526 0.816038 0.589091 +v 0.600394 0.842240 0.546292 +v 0.603688 0.846257 0.534938 +v 0.592912 0.848268 0.549156 +v 0.588755 0.846493 0.550192 +v 0.595852 0.838878 0.552781 +v 0.590916 0.852036 0.544576 +v 0.601288 0.849933 0.529686 +v 0.600945 0.854501 0.536006 +v 0.601057 0.846992 0.528684 +v 0.586584 0.837336 0.564284 +v 0.579771 0.842843 0.554327 +v 0.575393 0.853730 0.573226 +v 0.575268 0.849633 0.573943 +v 0.576975 0.853745 0.563064 +v 0.534160 0.917793 0.390875 +v 0.519247 0.923680 0.399711 +v 0.533425 0.925698 0.417184 +v 0.551980 0.920904 0.398885 +v 0.500959 0.927978 0.414843 +v 0.500959 0.917911 0.379589 +v 0.532104 0.894768 0.328593 +v 0.519588 0.912826 0.369297 +v 0.559773 0.904352 0.364757 +v 0.585961 0.913744 0.415351 +v 0.604190 0.900864 0.410872 +v 0.606558 0.897380 0.395712 +v 0.583957 0.907177 0.394781 +v 0.580957 0.880992 0.518993 +v 0.594997 0.867109 0.523977 +v 0.587739 0.821579 0.570956 +v 0.591965 0.870885 0.533045 +v 0.595640 0.870927 0.552962 +v 0.599170 0.860986 0.543085 +v 0.603392 0.848432 0.522700 +v 0.602207 0.853940 0.529814 +v 0.602775 0.835254 0.539135 +v 0.600128 0.829105 0.549855 +v 0.591084 0.874773 0.555053 +v 0.586303 0.874920 0.562388 +v 0.600643 0.861157 0.538356 +v 0.572783 0.852236 0.580202 +v 0.573388 0.841274 0.582107 +v 0.581119 0.830650 0.576886 +v 0.580315 0.858949 0.558068 +v 0.585254 0.859265 0.554969 +v 0.595194 0.827895 0.562224 +v 0.595746 0.901184 0.366039 +v 0.622929 0.883199 0.386557 +v 0.623997 0.881672 0.368419 +v 0.626819 0.880251 0.332545 +v 0.633202 0.873654 0.333145 +v 0.634606 0.874977 0.341895 +v 0.592585 0.900569 0.359293 +v 0.609445 0.893234 0.348493 +v 0.614858 0.888858 0.344468 +v 0.623451 0.883340 0.342741 +v 0.620786 0.888842 0.343091 +v 0.619921 0.885155 0.341968 +v 0.629846 0.875780 0.359533 +v 0.637840 0.867823 0.351352 +v 0.632521 0.877527 0.348615 +v 0.643349 0.855504 0.353592 +v 0.637608 0.856791 0.334081 +v 0.616579 0.885388 0.351231 +v 0.628479 0.879710 0.349049 +v 0.642770 0.839141 0.340438 +v 0.640329 0.839812 0.324915 +v 0.622811 0.882069 0.344702 +v 0.647476 0.803778 0.315416 +v 0.647754 0.823169 0.362236 +v 0.653231 0.793641 0.345457 +v 0.652128 0.806199 0.383725 +v 0.637540 0.860536 0.380182 +v 0.629630 0.881718 0.348456 +v 0.623213 0.880695 0.405048 +v 0.645819 0.831957 0.391880 +v 0.533889 0.841975 0.251119 +v 0.567747 0.884026 0.325027 +v 0.614841 0.891018 0.391397 +v 0.613915 0.891751 0.408020 +v 0.527516 0.863890 0.277651 +v 0.596158 0.901994 0.379047 +v 0.582740 0.904208 0.368515 +v 0.500959 0.901920 0.339023 +v 0.500959 0.862408 0.272231 +v 0.949940 0.092116 0.055824 +v 0.951567 0.085305 0.024386 +v 0.932348 0.106063 0.033444 +v 0.910137 0.124406 0.012176 +v 0.930559 0.102142 0.000274 +v 0.914387 0.114727 -0.008975 +v 0.897677 0.129585 0.003068 +v 0.906586 0.112725 0.012233 +v 0.872434 0.140488 0.025570 +v 0.889498 0.132352 0.005044 +v 0.890828 0.130067 0.037840 +v 0.939295 0.043195 0.095689 +v 0.902655 0.099719 0.044131 +v 0.910437 0.061839 0.099825 +v 0.889178 0.122318 0.017589 +v 0.897695 0.057329 0.117594 +v 0.879970 0.071654 0.110401 +v 0.892128 0.104663 0.044743 +v 0.960467 0.035656 0.066295 +v 0.941357 0.089486 0.106224 +v 0.912802 0.097744 0.137762 +v 0.951508 0.072066 0.126894 +v 0.980329 0.062888 0.091750 +v 0.969136 0.070796 0.102349 +v 0.971246 0.065495 0.108963 +v 0.990109 0.045336 0.103422 +v 0.957736 0.076464 0.110840 +v 0.908738 0.109532 0.127287 +v 0.962892 0.078622 0.089180 +v 0.994883 0.047621 0.076047 +v 0.900937 0.124113 0.065940 +v 0.910328 0.117014 0.102831 +v 0.858851 0.128491 0.008068 +v 0.860244 0.135371 -0.001668 +v 0.876353 0.134023 0.003512 +v 0.875371 0.096111 0.068141 +v 0.856173 0.092737 0.098545 +v 0.826095 0.114217 0.106363 +v 0.803124 0.132036 0.118425 +v 0.786788 0.142132 0.093974 +v 0.815567 0.148609 -0.041881 +v 0.822452 0.137752 -0.018269 +v 0.794416 0.158367 -0.062941 +v 0.834303 0.114966 0.070030 +v 0.838299 0.121087 0.039116 +v 0.840031 0.126901 0.015822 +v 0.818781 0.133214 0.023790 +v 0.841119 0.131878 -0.002176 +v 0.877038 0.111291 0.039289 +v 0.801961 0.164188 -0.075033 +v 0.763624 0.152393 0.034676 +v 0.783434 0.156374 -0.029448 +v 0.796376 0.141397 0.048095 +v 0.776738 0.148572 -0.076447 +v 0.788794 0.164586 -0.121597 +v 0.827490 0.141060 -0.023892 +v 0.843169 0.137157 -0.010635 +v 0.973125 0.053290 0.121650 +v 0.896822 0.047793 0.133902 +v 0.900475 0.038911 0.158281 +v 0.854503 0.085534 0.129552 +v 0.932699 0.025156 0.138466 +v 0.917437 0.030356 0.145849 +v 0.914627 0.034332 0.137145 +v 0.921390 0.027634 0.154414 +v 0.927357 0.033543 0.123994 +v 0.942886 0.024938 0.122549 +v 0.954213 0.023630 0.106792 +v 0.952208 0.017827 0.137801 +v 0.942470 0.021546 0.152360 +v 0.905799 0.039079 0.170000 +v 0.926034 0.027115 0.160901 +v 0.910430 0.042180 0.173377 +v 0.931027 0.029517 0.164004 +v 0.961373 0.015361 0.120190 +v 1.007780 -0.012791 0.083121 +v 0.991416 -0.001957 0.092461 +v 0.999965 -0.006966 0.072702 +v 0.995136 0.000941 0.060345 +v 0.937386 0.074466 0.022934 +v 0.960123 0.051647 0.011933 +v 1.001962 -0.000824 0.041407 +v 0.984280 0.023864 0.020652 +v 1.012946 -0.017298 0.065836 +v 0.972296 0.011088 0.100334 +v 0.982051 0.004179 0.113130 +v 0.917952 0.045858 0.170409 +v 0.940501 0.044616 0.156712 +v 0.925579 0.068349 0.153440 +v 0.883407 0.092193 0.175985 +v 0.958813 0.048830 0.139709 +v 0.970718 0.033366 0.138592 +v 0.967415 0.024862 0.143995 +v 0.984408 0.026897 0.127320 +v 0.981673 0.018812 0.132575 +v 0.985573 0.036634 0.119415 +v 0.972453 0.011483 0.132302 +v 0.977608 0.013360 0.134467 +v 0.962972 0.019082 0.145826 +v 0.743845 0.142870 0.006476 +v 0.596033 0.430219 -0.539039 +v 0.549922 0.309603 -0.980507 +v 0.601965 0.479901 -0.425577 +v 0.627638 0.399495 -0.520219 +v 0.528298 0.312275 -0.980514 +v 0.569483 0.027206 0.096935 +v 0.580805 0.024968 -0.024769 +v 0.640625 0.062758 0.019762 +v 0.629608 0.063647 0.095499 +v 0.500959 0.008169 0.012720 +v 0.500959 0.011507 0.094494 +v 0.500959 0.320208 -0.961314 +v 0.679712 0.107397 0.139966 +v 0.683327 0.106464 0.079729 +v 0.679002 0.398333 -0.378440 +v 0.667880 0.349028 -0.500041 +v 0.636059 0.446470 -0.407479 +v 0.733387 0.333842 -0.318567 +v 0.722645 0.286932 -0.433482 +v 0.688607 0.251859 -0.630556 +v 0.718992 0.142049 0.111226 +v 0.718607 0.142932 0.147125 +v 0.824224 0.113859 0.143959 +v 0.798027 0.140199 0.170492 +v 0.822118 0.117679 0.166533 +v 0.821125 0.123599 0.186677 +v 0.780704 0.146798 0.144278 +v 0.875399 0.061651 0.158468 +v 0.848927 0.089234 0.162934 +v 0.743755 0.154066 0.143060 +v 0.749321 0.151772 0.090465 +v 0.632903 0.059767 0.174579 +v 0.572259 0.025843 0.160559 +v 0.764875 0.150118 0.117172 +v 0.673815 0.057957 -0.110910 +v 0.653171 0.061935 -0.028314 +v 0.589388 0.023368 -0.086253 +v 0.591285 0.024022 -0.132010 +v 0.500959 0.007560 -0.075945 +v 0.671569 0.055882 -0.189925 +v 0.730110 0.103966 -0.167495 +v 0.598843 0.022873 -0.219800 +v 0.655202 0.050890 -0.342852 +v 0.631014 0.052353 -0.535744 +v 0.576337 0.028876 -0.549062 +v 0.552726 0.038759 -0.766145 +v 0.735445 0.107547 -0.091913 +v 0.753180 0.148261 -0.295449 +v 0.759386 0.202743 -0.356640 +v 0.781908 0.217298 -0.191178 +v 0.718103 0.199618 -0.578857 +v 0.714550 0.137107 -0.552993 +v 0.769706 0.266053 -0.242127 +v 0.590768 0.066590 -0.929892 +v 0.550780 0.051591 -0.931356 +v 0.710776 0.090313 -0.319904 +v 0.500959 0.028303 -0.777225 +v 0.500959 0.043788 -0.934640 +v 0.546154 0.268300 -1.105230 +v 0.546154 0.258115 -1.148150 +v 0.533346 0.249962 -1.143260 +v 0.531647 0.264605 -1.104290 +v 0.557990 0.260748 -1.150890 +v 0.559263 0.268252 -1.108790 +v 0.547325 0.283202 -1.059020 +v 0.533927 0.283534 -1.057010 +v 0.500959 0.281219 -1.052900 +v 0.516424 0.258873 -1.103200 +v 0.579412 0.247977 -1.111590 +v 0.570305 0.252866 -1.155910 +v 0.603964 0.228667 -1.054760 +v 0.583395 0.235417 -1.159760 +v 0.600143 0.202930 -1.157310 +v 0.598394 0.214533 -1.206790 +v 0.622220 0.186054 -1.064000 +v 0.619721 0.169622 -1.109950 +v 0.583805 0.236769 -1.203360 +v 0.605664 0.120802 -1.135460 +v 0.579030 0.111606 -1.128540 +v 0.623049 0.131987 -1.142220 +v 0.542196 0.106785 -1.122170 +v 0.578579 0.098962 -1.082760 +v 0.604233 0.111081 -1.086140 +v 0.620379 0.124431 -1.093750 +v 0.500959 0.083883 -1.078610 +v 0.544322 0.089545 -1.079910 +v 0.536393 0.067924 -1.026420 +v 0.574508 0.078701 -1.028760 +v 0.500959 0.063263 -1.025840 +v 0.518298 0.238252 -1.142490 +v 0.500959 0.244679 -1.118420 +v 0.500959 0.104017 -1.119160 +v 0.711017 0.051430 -1.354990 +v 0.708529 0.087978 -1.370930 +v 0.735734 0.096914 -1.406870 +v 0.763547 0.031893 -1.405760 +v 0.675320 0.159954 -1.344940 +v 0.569959 0.128237 -1.241200 +v 0.575322 0.107386 -1.234000 +v 0.633515 0.177227 -1.273020 +v 0.623182 0.157825 -1.155370 +v 0.628323 0.143448 -1.146830 +v 0.627904 0.137690 -1.098860 +v 0.997671 0.016831 0.113213 +v 0.992085 0.004620 0.119265 +v 0.995562 0.009491 0.117699 +v 1.000955 -0.005941 0.101294 +v 1.024133 -0.023356 0.065456 +v 1.014967 -0.012920 0.087697 +v 1.007825 -0.000623 0.101586 +v 1.018348 -0.004181 0.083461 +v 1.023765 -0.016391 0.074233 +v 1.017505 0.008996 0.071903 +v 1.009574 0.013604 0.092033 +v 1.026131 -0.022320 0.067024 +v 1.015921 -0.019811 0.049820 +v 0.968203 0.060058 0.010954 +v 0.954976 0.064369 -0.007183 +v 0.991314 0.036084 0.012247 +v 1.016481 0.013674 0.040846 +v 0.936756 0.081275 -0.000806 +v 0.979901 0.035749 0.003530 +v 0.970440 0.048691 -0.003225 +v 1.007612 0.026721 0.078685 +v 1.014047 0.018625 0.059113 +v 1.024520 -0.006963 0.065711 +v 1.022188 0.003520 0.053647 +v 1.024869 -0.025930 0.054792 +v 0.972849 0.051968 -0.003240 +v 0.602318 0.093369 -1.031890 +v 1.009610 -0.000985 0.016630 +v 1.017265 -0.020030 0.036118 +v 1.017331 -0.017195 0.025691 +v 1.010902 -0.011483 0.038721 +v 1.002180 0.003701 0.025520 +v 0.586867 0.812323 0.626830 +v 0.598022 0.808496 0.594699 +v 0.591948 0.815116 0.603779 +v 0.594231 0.803918 0.608406 +v 0.622316 0.768967 0.515548 +v 0.617019 0.753207 0.527468 +v 0.608615 0.749616 0.552266 +v 0.608883 0.774956 0.545606 +v 0.603231 0.775062 0.584965 +v 0.613473 0.773360 0.533488 +v 0.581618 0.795779 0.632662 +v 0.577269 0.775440 0.646654 +v 0.585876 0.779359 0.636249 +v 0.574649 0.792134 0.641440 +v 0.570261 0.781217 0.648212 +v 0.585787 0.789520 0.628134 +v 0.592134 0.781164 0.623401 +v 0.547048 0.812448 0.656397 +v 0.596981 0.780589 0.607116 +v 0.526732 0.612972 0.499928 +v 0.522977 0.597998 0.540358 +v 0.500959 0.597065 0.527521 +v 0.566833 0.649316 0.497236 +v 0.566424 0.632264 0.534842 +v 0.500959 0.594517 0.549916 +v 0.539917 0.610329 0.530997 +v 0.546378 0.626131 0.505547 +v 0.536446 0.604400 0.544818 +v 0.552475 0.633105 0.488746 +v 0.569588 0.650275 0.483807 +v 0.500959 0.605267 0.499228 +v 0.529107 0.611980 0.486880 +v 0.611003 0.722686 0.547671 +v 0.556970 0.618417 0.560331 +v 0.549889 0.613277 0.546128 +v 0.609736 0.738313 0.567939 +v 0.607107 0.755379 0.594459 +v 0.615207 0.729252 0.606539 +v 0.613354 0.739495 0.625802 +v 0.609851 0.749950 0.627566 +v 0.611649 0.746844 0.610376 +v 0.603064 0.760631 0.630124 +v 0.614502 0.728914 0.624833 +v 0.614165 0.717726 0.624312 +v 0.611521 0.720039 0.639044 +v 0.609064 0.705069 0.637860 +v 0.599380 0.770865 0.618646 +v 0.533996 0.603727 0.556265 +v 0.519978 0.598653 0.555657 +v 0.519023 0.602395 0.565435 +v 0.530392 0.609185 0.575125 +v 0.546456 0.610591 0.557713 +v 0.550034 0.618490 0.577321 +v 0.552703 0.628504 0.586310 +v 0.544572 0.620477 0.590838 +v 0.521916 0.817954 0.663830 +v 0.531300 0.814558 0.663484 +v 0.500959 0.609831 0.583194 +v 0.565151 0.629180 0.565392 +v 0.560763 0.627729 0.575637 +v 0.746981 0.387468 -0.185044 +v 0.714262 0.464423 -0.187055 +v 0.680491 0.543184 -0.112381 +v 0.653536 0.572974 -0.116409 +v 0.709880 0.493300 -0.132052 +v 0.763733 0.386116 -0.007327 +v 0.656683 0.549065 -0.181959 +v 0.681490 0.531445 -0.152152 +v 0.683837 0.503729 -0.210721 +v 0.820191 0.262709 0.052963 +v 0.810419 0.294508 0.007353 +v 0.819215 0.266816 -0.006062 +v 0.838737 0.213769 0.018545 +v 0.810185 0.177740 0.204557 +v 0.840617 0.159516 0.175365 +v 0.820540 0.207920 0.149263 +v 0.849123 0.202406 0.048961 +v 0.798589 0.288250 -0.075984 +v 0.573349 0.576930 -0.240725 +v 0.576209 0.605989 -0.158715 +v 0.600042 0.581230 -0.201967 +v 0.623932 0.548543 -0.246927 +v 0.552540 0.631825 -0.099755 +v 0.600969 0.613344 -0.110105 +v 0.627016 0.581492 -0.159678 +v 0.576354 0.624859 -0.104974 +v 0.551805 0.599405 -0.190114 +v 0.626863 0.596184 -0.114752 +v 0.500959 0.584703 -0.221703 +v 0.638800 0.059333 0.223220 +v 0.575442 0.028290 0.210805 +v 0.500959 0.011879 0.152427 +v 0.500959 0.016289 0.203257 +v 0.579585 0.039846 0.259094 +v 0.500959 0.030011 0.254332 +v 0.646564 0.067416 0.265813 +v 0.702415 0.111627 0.266499 +v 0.691906 0.104480 0.230265 +v 0.742790 0.151124 0.261356 +v 0.500959 0.603817 0.488784 +v 0.730272 0.143838 0.224986 +v 0.753828 0.157577 0.224428 +v 0.784270 0.167792 0.218476 +v 0.763823 0.164547 0.250578 +v 0.798829 0.156045 0.211664 +v 0.780750 0.156440 0.204504 +v 0.763892 0.154113 0.181416 +v 0.783279 0.197661 0.241803 +v 0.842990 0.205597 0.089710 +v 0.815902 0.201260 -0.051375 +v 0.803915 0.197811 -0.089403 +v 0.796754 0.260751 -0.102502 +v 0.831037 0.204174 -0.008625 +v 0.827571 0.177032 -0.024497 +v 0.813661 0.170258 -0.055443 +v 0.794646 0.235473 -0.123594 +v 0.777133 0.285228 -0.171493 +v 0.777448 0.325548 -0.132881 +v 0.853918 0.152320 0.009220 +v 0.844224 0.181012 0.009324 +v 0.865290 0.138737 0.006386 +v 0.865397 0.170921 0.049249 +v 0.609228 0.512399 -0.346300 +v 0.640454 0.482200 -0.335577 +v 0.649492 0.511732 -0.272903 +v 0.593061 0.553319 -0.284206 +v 0.713124 0.391738 -0.281242 +v 0.673413 0.447135 -0.309423 +v 0.583948 0.533629 -0.345425 +v 0.547780 0.571396 -0.274679 +v 0.525586 0.566766 -0.294075 +v 0.563147 0.550952 -0.326898 +v 0.747226 0.336726 -0.227401 +v 0.883099 0.069081 0.183331 +v 0.825319 0.140494 0.203731 +v 0.877058 0.066344 0.180677 +v 0.876710 0.061806 0.170998 +v 0.864957 0.176931 0.083569 +v 0.857041 0.173182 0.122428 +v 0.884937 0.141892 0.115530 +v 0.874868 0.130532 0.152221 +v 0.853305 0.104866 0.193093 +v 0.867303 0.121964 0.172120 +v 0.887789 0.144752 0.088243 +v 0.880118 0.142485 0.049213 +v 0.901405 0.095072 0.154464 +v 0.535456 0.617892 0.597101 +v 0.527754 0.614007 0.590637 +v 0.546259 0.629865 0.597292 +v 0.513613 0.807554 0.677676 +v 0.605063 0.704716 0.649470 +v 0.586631 0.744268 0.663230 +v 0.577161 0.735488 0.671309 +v 0.595522 0.729202 0.662421 +v 0.598872 0.703181 0.659361 +v 0.599322 0.717921 0.661243 +v 0.588493 0.715061 0.669620 +v 0.588866 0.701288 0.667763 +v 0.554976 0.738440 0.677121 +v 0.562643 0.751950 0.669574 +v 0.567942 0.770830 0.654899 +v 0.559987 0.780847 0.655043 +v 0.595742 0.760187 0.642959 +v 0.603663 0.750802 0.641474 +v 0.560833 0.800753 0.651987 +v 0.536441 0.741159 0.679594 +v 0.573240 0.699898 0.674780 +v 0.548087 0.687779 0.678268 +v 0.544564 0.724526 0.682002 +v 0.567652 0.721506 0.677235 +v 0.500959 0.563827 -0.293193 +v 0.500959 0.519066 -0.424287 +v 0.610727 0.731187 0.639845 +v 0.600305 0.740961 0.652810 +v 0.604240 0.731011 0.652176 +v 0.606542 0.719755 0.651118 +v 0.572528 0.711718 0.676312 +v 0.608371 0.741238 0.640473 +v 0.377701 0.612400 -0.022098 +v 0.376004 0.607367 -0.069014 +v 0.353293 0.584224 -0.022874 +v 0.379492 0.615149 0.024562 +v 0.356892 0.583679 0.027094 +v 0.401907 0.633451 -0.019058 +v 0.401357 0.626139 -0.064320 +v 0.350064 0.582058 -0.071430 +v 0.380721 0.619872 0.068976 +v 0.402348 0.638852 0.024721 +v 0.402430 0.646020 0.065866 +v 0.425203 0.663118 0.065216 +v 0.425576 0.654452 0.025856 +v 0.425709 0.647258 -0.016064 +v 0.449256 0.655534 -0.013169 +v 0.448610 0.673317 0.066216 +v 0.424394 0.676468 0.101079 +v 0.369431 0.673871 0.175641 +v 0.399188 0.679226 0.136156 +v 0.353411 0.623694 0.186300 +v 0.316698 0.488121 0.157681 +v 0.339548 0.532657 0.143786 +v 0.318993 0.499440 0.077679 +v 0.359686 0.585198 0.075460 +v 0.359298 0.592226 0.120005 +v 0.330339 0.529268 0.022292 +v 0.283085 0.429729 0.102893 +v 0.266171 0.443203 0.021558 +v 0.234631 0.357587 0.060284 +v 0.297242 0.506614 -0.052610 +v 0.446974 0.709072 0.130578 +v 0.323980 0.549850 -0.068618 +v 0.472787 0.651159 -0.047245 +v 0.472499 0.668863 0.029958 +v 0.364567 0.720835 0.428363 +v 0.351394 0.729935 0.402945 +v 0.356213 0.711159 0.403085 +v 0.380848 0.699067 0.437283 +v 0.370582 0.719152 0.446891 +v 0.360770 0.734438 0.437389 +v 0.443980 0.763425 0.179428 +v 0.469847 0.809866 0.215165 +v 0.471312 0.715022 0.130572 +v 0.471833 0.693110 0.102115 +v 0.352454 0.772879 0.427272 +v 0.354854 0.813190 0.419322 +v 0.344015 0.773937 0.373194 +v 0.373258 0.657994 0.401794 +v 0.366869 0.692856 0.408601 +v 0.359611 0.674393 0.396820 +v 0.334733 0.677767 0.376943 +v 0.344325 0.711868 0.387707 +v 0.355753 0.626225 0.391773 +v 0.336621 0.614071 0.379279 +v 0.332379 0.732202 0.346705 +v 0.330657 0.705588 0.365163 +v 0.472219 0.678824 0.068005 +v 0.425679 0.638481 -0.059939 +v 0.449367 0.645827 -0.055893 +v 0.294099 0.460174 0.268392 +v 0.299328 0.495500 0.302588 +v 0.307557 0.523166 0.238133 +v 0.302652 0.550846 0.272572 +v 0.301836 0.584918 0.302672 +v 0.305994 0.537320 0.330916 +v 0.354188 0.094418 0.303820 +v 0.368084 0.150559 0.338799 +v 0.297710 0.135856 0.297941 +v 0.315977 0.184096 0.330622 +v 0.244546 0.184639 0.280678 +v 0.279954 0.229895 0.316423 +v 0.292814 0.336066 0.327126 +v 0.320837 0.393474 0.358932 +v 0.287854 0.396374 0.299261 +v 0.305414 0.442387 0.332292 +v 0.320662 0.493680 0.357824 +v 0.342952 0.454585 0.381782 +v 0.345173 0.244975 0.364909 +v 0.390054 0.218512 0.373757 +v 0.376169 0.318415 0.395522 +v 0.403085 0.394058 0.417628 +v 0.344716 0.351238 0.380730 +v 0.421757 0.070379 0.303683 +v 0.429275 0.131033 0.342192 +v 0.413110 0.294990 0.404682 +v 0.432824 0.372703 0.427105 +v 0.375904 0.430596 0.405949 +v 0.441103 0.203776 0.378072 +v 0.311185 0.283910 0.349907 +v 0.260133 0.340041 0.224807 +v 0.286777 0.416705 0.189794 +v 0.250511 0.357198 0.138068 +v 0.231536 0.291480 0.178372 +v 0.227543 0.304855 0.111105 +v 0.247112 0.266209 0.256752 +v 0.267014 0.290673 0.292729 +v 0.226712 0.218492 0.242896 +v 0.200536 0.208065 0.194591 +v 0.212280 0.264465 0.153095 +v 0.170622 0.230390 0.075720 +v 0.290182 0.432497 0.230851 +v 0.313284 0.501236 0.200234 +v 0.272107 0.360164 0.263236 +v 0.404941 0.624244 0.406464 +v 0.404476 0.639432 0.409383 +v 0.470646 0.741263 0.155231 +v 0.420924 0.725044 0.158669 +v 0.418359 0.753412 0.183090 +v 0.449152 0.806221 0.216755 +v 0.424415 0.782889 0.206107 +v 0.395756 0.705766 0.164607 +v 0.391747 0.734188 0.190536 +v 0.403776 0.562633 0.409059 +v 0.450548 0.547939 0.439991 +v 0.411770 0.597824 0.409146 +v 0.353997 0.567478 0.390433 +v 0.374946 0.497066 0.403194 +v 0.429922 0.519115 0.428097 +v 0.458347 0.705405 0.682665 +v 0.391141 0.766583 0.221271 +v 0.419692 0.621158 0.415400 +v 0.330905 0.106237 -1.264430 +v 0.286681 0.058821 -1.325120 +v 0.327043 0.101718 -1.265780 +v 0.329409 0.095834 -1.262240 +v 0.295071 0.056073 -1.314110 +v 0.366239 0.144346 -1.203570 +v 0.341650 0.091532 -1.252910 +v 0.362647 0.091015 -1.239520 +v 0.379798 0.117071 -1.186240 +v 0.364914 0.124348 -1.194620 +v 0.310283 0.055055 -1.304740 +v 0.406579 0.111225 -1.176520 +v 0.459569 0.644569 0.606316 +v 0.462468 0.626716 0.603790 +v 0.471482 0.622635 0.609007 +v 0.476601 0.617291 0.603621 +v 0.487385 0.619256 0.610354 +v 0.473519 0.645271 0.619911 +v 0.471451 0.633329 0.616538 +v 0.486776 0.646610 0.627454 +v 0.482138 0.626398 0.616568 +v 0.466051 0.646658 0.611794 +v 0.360219 0.132379 -1.198970 +v 0.329478 0.545726 0.371350 +v 0.314223 0.584468 0.350867 +v 0.308373 0.625995 0.327591 +v 0.319052 0.668182 0.348150 +v 0.323855 0.632695 0.365273 +v 0.323445 0.702279 0.325073 +v 0.349312 0.750672 0.405428 +v 0.358857 0.749635 0.254416 +v 0.377203 0.777865 0.245260 +v 0.338516 0.758766 0.324642 +v 0.334741 0.735006 0.299631 +v 0.361347 0.779166 0.278920 +v 0.351028 0.511084 0.389312 +v 0.357492 0.728023 0.229496 +v 0.324237 0.580793 0.212475 +v 0.333458 0.559692 0.176404 +v 0.315458 0.606253 0.245304 +v 0.331129 0.670644 0.235268 +v 0.315041 0.668938 0.301330 +v 0.331115 0.710477 0.275139 +v 0.311075 0.635740 0.274926 +v 0.287656 0.464423 -0.187055 +v 0.259840 0.430617 -0.122691 +v 0.292038 0.493300 -0.132052 +v 0.291932 0.499696 -0.096210 +v 0.254937 0.387468 -0.185044 +v 0.227660 0.361262 -0.097142 +v 0.265365 0.447854 -0.056684 +v 0.238185 0.386116 -0.007327 +v 0.320428 0.531445 -0.152152 +v 0.321427 0.543184 -0.112381 +v 0.345235 0.549065 -0.181959 +v 0.348382 0.572974 -0.116409 +v 0.191499 0.294508 0.007353 +v 0.203329 0.288250 -0.075984 +v 0.181378 0.207920 0.149263 +v 0.161301 0.159516 0.175365 +v 0.191733 0.177740 0.204557 +v 0.163181 0.213769 0.018545 +v 0.181727 0.262709 0.052963 +v 0.182703 0.266816 -0.006062 +v 0.152795 0.202406 0.048961 +v 0.158928 0.205597 0.089710 +v 0.318081 0.503729 -0.210721 +v 0.449378 0.631825 -0.099755 +v 0.428569 0.576930 -0.240725 +v 0.377986 0.548543 -0.246927 +v 0.401876 0.581230 -0.201967 +v 0.472685 0.615378 -0.148421 +v 0.375055 0.596184 -0.114752 +v 0.400949 0.613344 -0.110105 +v 0.374902 0.581492 -0.159678 +v 0.450113 0.599405 -0.190114 +v 0.425709 0.605989 -0.158715 +v 0.473936 0.587551 -0.226392 +v 0.491328 0.842317 0.633935 +v 0.425564 0.624859 -0.104974 +v 0.422333 0.039846 0.259094 +v 0.426476 0.028290 0.210805 +v 0.475186 0.612972 0.499928 +v 0.472811 0.611980 0.486880 +v 0.355354 0.067416 0.265813 +v 0.429659 0.025843 0.160559 +v 0.432435 0.027206 0.096935 +v 0.363118 0.059333 0.223220 +v 0.369015 0.059767 0.174579 +v 0.432330 0.650275 0.483807 +v 0.415964 0.666200 0.476135 +v 0.449443 0.633105 0.488746 +v 0.411456 0.673160 0.487305 +v 0.395203 0.684627 0.450204 +v 0.448224 0.621327 0.474042 +v 0.435085 0.649316 0.497236 +v 0.455540 0.626131 0.505547 +v 0.462001 0.610329 0.530997 +v 0.435494 0.632264 0.534842 +v 0.471449 0.601755 0.475099 +v 0.420674 0.666419 0.489475 +v 0.422735 0.664070 0.500481 +v 0.299503 0.111627 0.266499 +v 0.259128 0.151124 0.261356 +v 0.238095 0.164547 0.250578 +v 0.271646 0.143838 0.224986 +v 0.248090 0.157577 0.224428 +v 0.221168 0.156440 0.204504 +v 0.217648 0.167792 0.218476 +v 0.218639 0.197661 0.241803 +v 0.198794 0.132036 0.118425 +v 0.215130 0.142132 0.093974 +v 0.221214 0.146798 0.144278 +v 0.238026 0.154113 0.181416 +v 0.203891 0.140199 0.170492 +v 0.203089 0.156045 0.211664 +v 0.258163 0.154066 0.143060 +v 0.310012 0.104480 0.230265 +v 0.322206 0.107397 0.139966 +v 0.283311 0.142932 0.147125 +v 0.372310 0.063647 0.095499 +v 0.443514 0.923740 0.437056 +v 0.466188 0.920970 0.473392 +v 0.413492 0.647184 0.424975 +v 0.385952 0.670834 0.415311 +v 0.395258 0.687594 0.468165 +v 0.391485 0.691248 0.456331 +v 0.475584 0.583887 0.462473 +v 0.452163 0.608863 0.459715 +v 0.436119 0.620678 0.439879 +v 0.378509 0.707404 0.485958 +v 0.385329 0.696836 0.474545 +v 0.375602 0.722931 0.499593 +v 0.366563 0.746019 0.482765 +v 0.361330 0.802033 0.457857 +v 0.364691 0.770833 0.483735 +v 0.397067 0.683557 0.480779 +v 0.381625 0.701474 0.499688 +v 0.377188 0.741230 0.511800 +v 0.452281 0.585078 0.443153 +v 0.463947 0.358626 0.432701 +v 0.470187 0.428115 0.445782 +v 0.453456 0.280949 0.409583 +v 0.467874 0.466177 0.448708 +v 0.454768 0.599294 0.451822 +v 0.476905 0.561451 0.457477 +v 0.445666 0.827116 0.630153 +v 0.438243 0.836801 0.596703 +v 0.432472 0.826824 0.614558 +v 0.447392 0.837975 0.609469 +v 0.470431 0.880189 0.550502 +v 0.469797 0.896206 0.532757 +v 0.458120 0.883801 0.546303 +v 0.446832 0.844310 0.598316 +v 0.457312 0.828857 0.635023 +v 0.475086 0.855288 0.612069 +v 0.433558 0.820700 0.635800 +v 0.425586 0.828011 0.587678 +v 0.419928 0.821482 0.609257 +v 0.455240 0.904902 0.519684 +v 0.446668 0.890614 0.536255 +v 0.439446 0.883759 0.545254 +v 0.455670 0.864357 0.567246 +v 0.450818 0.852811 0.587916 +v 0.443898 0.848361 0.590624 +v 0.478914 0.894433 0.536944 +v 0.448495 0.913879 0.485951 +v 0.489094 0.893524 0.542171 +v 0.484261 0.877070 0.560208 +v 0.467331 0.907407 0.514522 +v 0.421400 0.818178 0.627616 +v 0.491294 0.833647 0.646428 +v 0.459473 0.822898 0.647488 +v 0.426962 0.813182 0.640316 +v 0.407659 0.908739 0.430808 +v 0.419446 0.911205 0.460406 +v 0.430499 0.920352 0.428670 +v 0.374036 0.785050 0.501029 +v 0.396672 0.795599 0.537784 +v 0.375020 0.805028 0.489048 +v 0.379800 0.837858 0.484492 +v 0.394367 0.836710 0.514872 +v 0.368817 0.845261 0.439745 +v 0.386410 0.854841 0.483344 +v 0.393895 0.876964 0.457550 +v 0.428942 0.895093 0.504646 +v 0.422957 0.905367 0.480873 +v 0.404185 0.866787 0.508792 +v 0.392396 0.850004 0.513888 +v 0.364559 0.852603 0.413964 +v 0.434151 0.895833 0.516652 +v 0.438671 0.903479 0.508477 +v 0.434591 0.909953 0.485149 +v 0.434001 0.916119 0.464188 +v 0.427470 0.887689 0.528008 +v 0.404451 0.683590 0.646857 +v 0.410397 0.662534 0.634190 +v 0.410435 0.683112 0.656408 +v 0.400438 0.683758 0.635974 +v 0.447171 0.644216 0.653538 +v 0.421318 0.663481 0.653196 +v 0.429901 0.640209 0.640469 +v 0.434979 0.685148 0.672401 +v 0.420012 0.683300 0.664877 +v 0.430725 0.665814 0.661613 +v 0.444859 0.670800 0.669618 +v 0.390785 0.698299 0.606768 +v 0.400653 0.672017 0.601692 +v 0.398271 0.682840 0.623260 +v 0.392734 0.694070 0.548934 +v 0.395871 0.683798 0.570210 +v 0.388883 0.705454 0.585914 +v 0.390063 0.712161 0.564874 +v 0.420346 0.640511 0.624027 +v 0.462352 0.654879 0.665402 +v 0.376759 0.873365 0.319768 +v 0.386398 0.888308 0.335356 +v 0.393911 0.863550 0.304554 +v 0.413372 0.893863 0.347633 +v 0.413384 0.887470 0.325737 +v 0.423597 0.857041 0.286978 +v 0.432489 0.836503 0.254958 +v 0.398206 0.822405 0.263633 +v 0.377178 0.802202 0.262298 +v 0.379670 0.829489 0.281685 +v 0.390314 0.797542 0.241193 +v 0.410122 0.805541 0.233751 +v 0.375953 0.891315 0.346821 +v 0.388439 0.895185 0.344574 +v 0.383792 0.897533 0.345906 +v 0.381321 0.893734 0.340280 +v 0.375291 0.888216 0.340726 +v 0.474629 0.663128 0.672820 +v 0.394974 0.898533 0.344743 +v 0.378637 0.889390 0.337053 +v 0.383387 0.893241 0.338626 +v 0.405601 0.657078 0.559205 +v 0.396969 0.668669 0.537240 +v 0.402778 0.657870 0.541576 +v 0.422362 0.639509 0.566166 +v 0.399631 0.668671 0.550972 +v 0.403019 0.661004 0.531148 +v 0.391012 0.686146 0.525432 +v 0.398162 0.672062 0.518929 +v 0.386753 0.690621 0.489434 +v 0.390125 0.685746 0.503521 +v 0.396023 0.681139 0.491830 +v 0.420738 0.649273 0.530996 +v 0.420558 0.642241 0.552658 +v 0.416322 0.652152 0.593939 +v 0.406889 0.664441 0.586828 +v 0.409210 0.657077 0.573150 +v 0.417128 0.647810 0.604270 +v 0.410506 0.671313 0.498831 +v 0.386560 0.714573 0.526956 +v 0.384645 0.701743 0.513483 +v 0.368716 0.873654 0.333145 +v 0.375099 0.880251 0.332545 +v 0.367312 0.874977 0.341895 +v 0.392473 0.893234 0.348493 +v 0.387060 0.888858 0.344468 +v 0.381997 0.885155 0.341968 +v 0.381132 0.888842 0.343091 +v 0.378467 0.883340 0.342741 +v 0.406172 0.901184 0.366039 +v 0.409333 0.900569 0.359293 +v 0.367845 0.863179 0.322904 +v 0.369397 0.877527 0.348615 +v 0.372072 0.875780 0.359533 +v 0.373439 0.879710 0.349049 +v 0.377921 0.881672 0.368419 +v 0.364078 0.867823 0.351352 +v 0.379107 0.882069 0.344702 +v 0.385339 0.885388 0.351231 +v 0.361589 0.839812 0.324915 +v 0.364310 0.856791 0.334081 +v 0.370876 0.843568 0.308472 +v 0.358569 0.855504 0.353592 +v 0.359148 0.839141 0.340438 +v 0.354164 0.823169 0.362236 +v 0.354442 0.803778 0.315416 +v 0.348687 0.793641 0.345457 +v 0.366208 0.816014 0.290448 +v 0.364378 0.860536 0.380182 +v 0.349790 0.806199 0.383725 +v 0.372288 0.881718 0.348456 +v 0.397728 0.900864 0.410872 +v 0.391633 0.892979 0.422739 +v 0.378705 0.880695 0.405048 +v 0.485785 0.755355 0.681493 +v 0.483986 0.762112 0.678942 +v 0.475393 0.764191 0.673428 +v 0.485345 0.760788 0.687626 +v 0.487391 0.751469 0.686990 +v 0.493507 0.735803 0.692192 +v 0.490196 0.747013 0.692986 +v 0.487272 0.743301 0.683944 +v 0.485099 0.722971 0.686030 +v 0.491936 0.728898 0.690558 +v 0.455344 0.767573 0.673794 +v 0.452684 0.767505 0.666335 +v 0.452719 0.772233 0.679382 +v 0.451141 0.770479 0.671603 +v 0.449611 0.776705 0.680478 +v 0.448168 0.781498 0.679623 +v 0.447018 0.781183 0.675530 +v 0.459576 0.769081 0.681210 +v 0.487570 0.756700 0.691463 +v 0.468058 0.766707 0.695891 +v 0.468538 0.762758 0.694788 +v 0.476655 0.760291 0.698989 +v 0.460807 0.772748 0.692093 +v 0.461706 0.769607 0.692429 +v 0.485388 0.751626 0.695725 +v 0.466825 0.769087 0.687834 +v 0.486326 0.754873 0.701007 +v 0.450270 0.771618 0.668907 +v 0.374248 0.097594 -0.929001 +v 0.361777 0.158908 -0.965177 +v 0.388076 0.288941 -0.845986 +v 0.406646 0.366988 -0.687265 +v 0.428860 0.334294 -0.851999 +v 0.426040 0.282727 -1.007290 +v 0.347004 0.233473 -0.822363 +v 0.356280 0.316935 -0.654736 +v 0.378911 0.215767 -0.983395 +v 0.334842 0.178443 -0.793621 +v 0.327142 0.135663 -0.733262 +v 0.460006 0.361342 -0.829636 +v 0.454376 0.405265 -0.684268 +v 0.440084 0.018629 -0.375238 +v 0.445782 0.458570 -0.540649 +v 0.451297 0.512050 -0.425986 +v 0.380026 0.070306 -0.754434 +v 0.447395 0.785466 0.672168 +v 0.448956 0.778924 0.666079 +v 0.450229 0.773819 0.661913 +v 0.465068 0.800824 0.668946 +v 0.474605 0.800115 0.676258 +v 0.479174 0.811211 0.670668 +v 0.449856 0.785617 0.660033 +v 0.448851 0.788875 0.667964 +v 0.454290 0.795278 0.662622 +v 0.328838 0.085114 -0.561076 +v 0.487683 0.798064 0.685637 +v 0.487819 0.775988 0.696147 +v 0.466691 0.795020 0.676064 +v 0.470924 0.784508 0.687531 +v 0.443622 0.646077 0.593129 +v 0.432747 0.643672 0.579752 +v 0.452346 0.775454 0.684632 +v 0.459100 0.770882 0.687157 +v 0.455136 0.777113 0.688024 +v 0.451756 0.785546 0.679611 +v 0.448801 0.786291 0.675699 +v 0.450708 0.790437 0.670699 +v 0.456579 0.794874 0.668868 +v 0.405760 0.901994 0.379047 +v 0.395360 0.897380 0.395712 +v 0.421235 0.880287 0.554143 +v 0.415615 0.874920 0.562388 +v 0.424892 0.874849 0.564659 +v 0.420256 0.869117 0.570583 +v 0.410834 0.874773 0.555053 +v 0.406278 0.870927 0.552962 +v 0.415722 0.871845 0.563035 +v 0.428726 0.867143 0.573768 +v 0.426840 0.859459 0.579210 +v 0.420490 0.865570 0.568831 +v 0.406921 0.867109 0.523977 +v 0.401275 0.861157 0.538356 +v 0.409953 0.870885 0.533045 +v 0.402748 0.860986 0.543085 +v 0.399711 0.853940 0.529814 +v 0.400973 0.854501 0.536006 +v 0.435918 0.855952 0.582075 +v 0.436695 0.850776 0.584834 +v 0.432154 0.860735 0.579794 +v 0.436757 0.844871 0.588505 +v 0.415334 0.837336 0.564284 +v 0.406724 0.827895 0.562224 +v 0.414179 0.821579 0.570956 +v 0.407442 0.820713 0.559667 +v 0.424326 0.843243 0.573824 +v 0.420799 0.830650 0.576886 +v 0.401790 0.829105 0.549855 +v 0.398375 0.823134 0.532214 +v 0.402786 0.816423 0.543682 +v 0.429135 0.852236 0.580202 +v 0.428530 0.841274 0.582107 +v 0.433928 0.838564 0.587199 +v 0.426650 0.849633 0.573943 +v 0.426525 0.853730 0.573226 +v 0.406066 0.838878 0.552781 +v 0.400630 0.849933 0.529686 +v 0.398526 0.848432 0.522700 +v 0.400861 0.846992 0.528684 +v 0.401524 0.842240 0.546292 +v 0.399143 0.835254 0.539135 +v 0.397956 0.827246 0.525154 +v 0.398230 0.846257 0.534938 +v 0.367327 0.203091 -1.315050 +v 0.333394 0.175087 -1.354480 +v 0.426902 0.205314 -1.239180 +v 0.469093 0.214628 -1.183750 +v 0.443652 0.242684 -1.193470 +v 0.410750 0.221597 -1.254470 +v 0.458579 0.230331 -1.184290 +v 0.389889 0.088463 -1.228880 +v 0.439515 0.110026 -1.168370 +v 0.264920 0.025631 -1.355470 +v 0.288040 0.032509 -1.338010 +v -0.028001 -0.026848 0.035993 +v -0.026285 -0.024766 0.028007 +v -0.024018 -0.027362 0.028465 +v 0.459616 0.856474 0.587046 +v 0.458609 0.846764 0.608747 +v 0.465896 0.864632 0.567497 +v 0.476060 0.881787 0.549029 +v 0.474948 0.872380 0.561206 +v -0.014102 0.004271 0.013013 +v -0.006958 0.018583 0.008055 +v 0.008101 0.039208 -0.007447 +v -0.020540 -0.026258 0.034935 +v -0.026147 -0.028822 0.036488 +v -0.029759 -0.027256 0.050523 +v -0.027260 -0.019200 0.033938 +v -0.021798 -0.023392 0.023353 +v -0.022812 -0.007459 0.025607 +v -0.024303 -0.020103 0.023091 +v -0.000616 0.012276 0.009291 +v -0.012012 -0.000455 0.012509 +v 0.007011 0.026470 0.001472 +v -0.021846 -0.013473 0.019867 +v -0.018767 0.003655 0.026927 +v -0.020471 -0.025511 0.048231 +v -0.027818 -0.028638 0.044417 +v 0.356099 0.831957 0.391880 +v 0.378989 0.883199 0.386557 +v 0.415957 0.913744 0.415351 +v 0.449938 0.920904 0.398885 +v 0.417961 0.907177 0.394781 +v 0.467758 0.917793 0.390875 +v 0.442145 0.904352 0.364757 +v 0.482671 0.923680 0.399711 +v 0.468493 0.925698 0.417184 +v 0.387077 0.891018 0.391397 +v 0.388003 0.891751 0.408020 +v 0.419178 0.904208 0.368515 +v 0.434171 0.884026 0.325027 +v 0.482330 0.912826 0.369297 +v 0.474402 0.863890 0.277651 +v 0.468029 0.841975 0.251119 +v 0.469814 0.894768 0.328593 +v 0.413163 0.846493 0.550192 +v 0.422147 0.842843 0.554327 +v 0.425804 0.844084 0.559554 +v 0.409006 0.848268 0.549156 +v 0.411002 0.852036 0.544576 +v 0.396504 0.811799 0.520603 +v 0.427505 0.849637 0.563428 +v 0.424943 0.853745 0.563064 +v 0.416664 0.859265 0.554969 +v 0.421603 0.858949 0.558068 +v 0.420961 0.880992 0.518993 +v 0.406560 0.812052 0.569266 +v 0.409540 0.813531 0.577899 +v 0.411392 0.816038 0.589091 +v 0.400634 0.800118 0.571778 +v 0.089116 0.097744 0.137762 +v 0.060561 0.089486 0.106224 +v 0.050410 0.072066 0.126894 +v 0.032782 0.070796 0.102349 +v 0.021589 0.062888 0.091750 +v 0.030672 0.065495 0.108963 +v 0.011809 0.045336 0.103422 +v 0.044182 0.076464 0.110840 +v 0.039026 0.078622 0.089180 +v 0.100981 0.124113 0.065940 +v 0.091590 0.117014 0.102831 +v 0.051978 0.092116 0.055824 +v 0.007035 0.047621 0.076047 +v 0.069570 0.106063 0.033444 +v 0.093180 0.109532 0.127287 +v 0.031200 0.033366 0.138592 +v 0.034503 0.024862 0.143995 +v 0.043105 0.048830 0.139709 +v 0.061417 0.044616 0.156712 +v 0.028793 0.053290 0.121650 +v 0.016345 0.036634 0.119415 +v 0.017510 0.026897 0.127320 +v 0.083966 0.045858 0.170409 +v 0.076339 0.068349 0.153440 +v 0.118511 0.092193 0.175985 +v 0.104223 0.057329 0.117594 +v 0.091481 0.061839 0.099825 +v 0.121948 0.071654 0.110401 +v 0.141674 0.135371 -0.001668 +v 0.143067 0.128491 0.008068 +v 0.125565 0.134023 0.003512 +v 0.112740 0.122318 0.017589 +v 0.109790 0.104663 0.044743 +v 0.099263 0.099719 0.044131 +v 0.062623 0.043195 0.095689 +v 0.095332 0.112725 0.012233 +v 0.104241 0.129585 0.003068 +v 0.126547 0.096111 0.068141 +v 0.124880 0.111291 0.039289 +v 0.163619 0.121087 0.039116 +v 0.161887 0.126901 0.015822 +v 0.112420 0.132352 0.005044 +v 0.111090 0.130067 0.037840 +v 0.129484 0.140488 0.025570 +v 0.091781 0.124406 0.012176 +v 0.087531 0.114727 -0.008975 +v 0.041451 0.035656 0.066295 +v 0.050351 0.085305 0.024386 +v 0.071359 0.102142 0.000274 +v 0.074561 0.033543 0.123994 +v 0.059032 0.024938 0.122549 +v 0.047705 0.023630 0.106792 +v 0.080528 0.027634 0.154414 +v 0.084481 0.030356 0.145849 +v 0.101443 0.038911 0.158281 +v 0.105096 0.047793 0.133902 +v 0.087291 0.034332 0.137145 +v 0.069219 0.025156 0.138466 +v 0.049710 0.017827 0.137801 +v 0.059448 0.021546 0.152360 +v 0.147415 0.085534 0.129552 +v 0.001953 -0.006966 0.072702 +v -0.011028 -0.017298 0.065836 +v 0.006782 0.000941 0.060345 +v 0.041795 0.051647 0.011933 +v 0.064532 0.074466 0.022934 +v 0.031478 0.048691 -0.003225 +v 0.046942 0.064369 -0.007183 +v -0.000044 -0.000824 0.041407 +v 0.017638 0.023864 0.020652 +v 0.040545 0.015361 0.120190 +v 0.019867 0.004179 0.113130 +v 0.029622 0.011088 0.100334 +v 0.010502 -0.001957 0.092461 +v -0.005862 -0.012791 0.083121 +v 0.070891 0.029517 0.164004 +v 0.024310 0.013360 0.134467 +v 0.029465 0.011483 0.132302 +v 0.038946 0.019082 0.145826 +v 0.091488 0.042180 0.173377 +v 0.020245 0.018812 0.132575 +v 0.075884 0.027115 0.160901 +v 0.096119 0.039079 0.170000 +v 0.291142 0.090313 -0.319904 +v 0.287368 0.137107 -0.552993 +v 0.370904 0.052353 -0.535744 +v 0.346716 0.050890 -0.342852 +v 0.248738 0.148261 -0.295449 +v 0.242532 0.202743 -0.356640 +v 0.220010 0.217298 -0.191178 +v 0.213124 0.164586 -0.121597 +v 0.283815 0.199618 -0.578857 +v 0.411150 0.066590 -0.929892 +v 0.232212 0.266053 -0.242127 +v 0.279273 0.286932 -0.433482 +v 0.271808 0.103966 -0.167495 +v 0.330349 0.055882 -0.189925 +v 0.449192 0.038759 -0.766145 +v 0.425581 0.028876 -0.549062 +v 0.451138 0.051591 -0.931356 +v 0.334038 0.349028 -0.500041 +v 0.374280 0.399495 -0.520219 +v 0.313311 0.251859 -0.630556 +v 0.322916 0.398333 -0.378440 +v 0.365859 0.446470 -0.407479 +v 0.268531 0.333842 -0.318567 +v 0.405885 0.430219 -0.539039 +v 0.399953 0.479901 -0.425577 +v 0.218484 0.156374 -0.029448 +v 0.183137 0.133214 0.023790 +v 0.179466 0.137752 -0.018269 +v 0.205542 0.141397 0.048095 +v 0.167615 0.114966 0.070030 +v 0.186351 0.148609 -0.041881 +v 0.207502 0.158367 -0.062941 +v 0.199957 0.164188 -0.075033 +v 0.174428 0.141060 -0.023892 +v 0.225180 0.148572 -0.076447 +v 0.258073 0.142870 0.006476 +v 0.238294 0.152393 0.034676 +v 0.175823 0.114217 0.106363 +v 0.160799 0.131878 -0.002176 +v 0.158749 0.137157 -0.010635 +v 0.145745 0.092737 0.098545 +v 0.410633 0.024022 -0.132010 +v 0.412530 0.023368 -0.086253 +v 0.328103 0.057957 -0.110910 +v 0.348747 0.061935 -0.028314 +v 0.403075 0.022873 -0.219800 +v 0.266473 0.107547 -0.091913 +v 0.421113 0.024968 -0.024769 +v 0.361293 0.062758 0.019762 +v 0.318591 0.106464 0.079729 +v 0.022017 0.035749 0.003530 +v 0.396254 0.120802 -1.135460 +v 0.422888 0.111606 -1.128540 +v 0.397685 0.111081 -1.086140 +v 0.423339 0.098962 -1.082760 +v 0.459722 0.106785 -1.122170 +v 0.457596 0.089545 -1.079910 +v 0.378869 0.131987 -1.142220 +v 0.465525 0.067924 -1.026420 +v 0.485494 0.258873 -1.103200 +v 0.483620 0.238252 -1.142490 +v 0.470271 0.264605 -1.104290 +v 0.468572 0.249962 -1.143260 +v -0.007692 -0.000985 0.016630 +v 0.399600 0.093369 -1.031890 +v -0.015347 -0.020030 0.036118 +v -0.015413 -0.017195 0.025691 +v -0.021847 -0.016391 0.074233 +v -0.024213 -0.022320 0.067024 +v -0.022602 -0.006963 0.065711 +v -0.016430 -0.004181 0.083461 +v -0.013049 -0.012920 0.087697 +v 0.427410 0.078701 -1.028760 +v 0.467991 0.283534 -1.057010 +v 0.431613 0.252866 -1.155910 +v 0.418523 0.235417 -1.159760 +v 0.422506 0.247977 -1.111590 +v 0.401775 0.202930 -1.157310 +v 0.397954 0.228667 -1.054760 +v 0.378736 0.157825 -1.155370 +v 0.379698 0.186054 -1.064000 +v 0.442655 0.268252 -1.108790 +v 0.373595 0.143448 -1.146830 +v 0.455764 0.258115 -1.148150 +v 0.443928 0.260748 -1.150890 +v 0.455764 0.268300 -1.105230 +v 0.454593 0.283202 -1.059020 +v 0.473620 0.312275 -0.980514 +v 0.451996 0.309603 -0.980507 +v -0.020270 0.003520 0.053647 +v -0.005907 -0.000623 0.101586 +v -0.007656 0.013604 0.092033 +v 0.006356 0.009491 0.117699 +v 0.009833 0.004620 0.119265 +v -0.015587 0.008996 0.071903 +v -0.005694 0.026721 0.078685 +v 0.004247 0.016831 0.113213 +v 0.000963 -0.005941 0.101294 +v -0.014003 -0.019811 0.049820 +v -0.022215 -0.023356 0.065456 +v 0.033715 0.060058 0.010954 +v -0.014563 0.013674 0.040846 +v 0.010604 0.036084 0.012247 +v 0.065162 0.081275 -0.000806 +v -0.012129 0.018625 0.059113 +v -0.000262 0.003701 0.025520 +v -0.008984 -0.011483 0.038721 +v 0.029069 0.051968 -0.003240 +v -0.022951 -0.025930 0.054792 +v 0.441085 0.800753 0.651987 +v 0.441931 0.780847 0.655043 +v 0.431657 0.781217 0.648212 +v 0.454870 0.812448 0.656397 +v 0.433976 0.770830 0.654899 +v 0.439275 0.751950 0.669574 +v 0.427269 0.792134 0.641440 +v 0.470618 0.814558 0.663484 +v 0.474164 0.614007 0.590637 +v 0.471526 0.609185 0.575125 +v 0.488305 0.807554 0.677676 +v 0.480002 0.817954 0.663830 +v 0.402538 0.770865 0.618646 +v 0.404937 0.780589 0.607116 +v 0.394811 0.755379 0.594459 +v 0.420300 0.795779 0.632662 +v 0.415051 0.812323 0.626830 +v 0.416131 0.789520 0.628134 +v 0.409784 0.781164 0.623401 +v 0.416042 0.779359 0.636249 +v 0.393303 0.749616 0.552266 +v 0.398687 0.775062 0.584965 +v 0.393035 0.774956 0.545606 +v 0.407687 0.803918 0.608406 +v 0.390269 0.746844 0.610376 +v 0.386711 0.729252 0.606539 +v 0.398854 0.760631 0.630124 +v 0.390915 0.722686 0.547671 +v 0.392182 0.738313 0.567939 +v 0.424649 0.775440 0.646654 +v 0.415287 0.744268 0.663230 +v 0.406176 0.760187 0.642959 +v 0.424757 0.735488 0.671309 +v 0.446942 0.738440 0.677121 +v 0.392067 0.749950 0.627566 +v 0.398255 0.750802 0.641474 +v 0.457346 0.620477 0.590838 +v 0.390397 0.720039 0.639044 +v 0.391191 0.731187 0.639845 +v 0.387753 0.717726 0.624312 +v 0.387416 0.728914 0.624833 +v 0.395376 0.719755 0.651118 +v 0.397678 0.731011 0.652176 +v 0.406396 0.729202 0.662421 +v 0.401613 0.740961 0.652810 +v 0.402596 0.717921 0.661243 +v 0.396855 0.704716 0.649470 +v 0.403046 0.703181 0.659361 +v 0.392854 0.705069 0.637860 +v 0.428678 0.699898 0.674780 +v 0.429390 0.711718 0.676312 +v 0.413052 0.701288 0.667763 +v 0.393547 0.741238 0.640473 +v 0.388564 0.739495 0.625802 +v 0.457354 0.724526 0.682002 +v 0.434266 0.721506 0.677235 +v 0.413425 0.715061 0.669620 +v 0.466462 0.617892 0.597101 +v 0.449215 0.628504 0.586310 +v 0.455659 0.629865 0.597292 +v 0.451884 0.618490 0.577321 +v 0.452029 0.613277 0.546128 +v 0.444948 0.618417 0.560331 +v 0.478941 0.597998 0.540358 +v 0.465472 0.604400 0.544818 +v 0.403896 0.808496 0.594699 +v 0.409970 0.815116 0.603779 +v 0.379602 0.768967 0.515548 +v 0.388445 0.773360 0.533488 +v 0.384899 0.753207 0.527468 +v 0.436767 0.629180 0.565392 +v 0.441155 0.627729 0.575637 +v 0.482895 0.602395 0.565435 +v 0.481940 0.598653 0.555657 +v 0.467922 0.603727 0.556265 +v 0.455462 0.610591 0.557713 +v 0.176599 0.140494 0.203731 +v 0.148613 0.104866 0.193093 +v 0.134615 0.121964 0.172120 +v 0.118819 0.069081 0.183331 +v 0.144877 0.173182 0.122428 +v 0.136961 0.176931 0.083569 +v 0.116981 0.141892 0.115530 +v 0.127050 0.130532 0.152221 +v 0.124860 0.066344 0.180677 +v 0.180793 0.123599 0.186677 +v 0.126519 0.061651 0.158468 +v 0.125208 0.061806 0.170998 +v 0.136521 0.170921 0.049249 +v 0.121800 0.142485 0.049213 +v 0.114129 0.144752 0.088243 +v 0.100513 0.095072 0.154464 +v 0.177694 0.113859 0.143959 +v 0.152991 0.089234 0.162934 +v 0.282926 0.142049 0.111226 +v 0.252597 0.151772 0.090465 +v 0.237043 0.150118 0.117172 +v 0.179800 0.117679 0.166533 +v 0.465477 0.741159 0.679594 +v 0.453831 0.687779 0.678268 +v 0.352426 0.511732 -0.272903 +v 0.392690 0.512399 -0.346300 +v 0.361464 0.482200 -0.335577 +v 0.288794 0.391738 -0.281242 +v 0.328505 0.447135 -0.309423 +v 0.408857 0.553319 -0.284206 +v 0.417970 0.533629 -0.345425 +v 0.438771 0.550952 -0.326898 +v 0.476332 0.566766 -0.294075 +v 0.454138 0.571396 -0.274679 +v 0.188257 0.170258 -0.055443 +v 0.174347 0.177032 -0.024497 +v 0.186016 0.201260 -0.051375 +v 0.157694 0.181012 0.009324 +v 0.170881 0.204174 -0.008625 +v 0.207272 0.235473 -0.123594 +v 0.198003 0.197811 -0.089403 +v 0.205164 0.260751 -0.102502 +v 0.148000 0.152320 0.009220 +v 0.136628 0.138737 0.006386 +v 0.254692 0.336726 -0.227401 +v 0.224785 0.285228 -0.171493 +v 0.224470 0.325548 -0.132881 +vt 0.5688 0.8211 +vt 0.5964 0.8460 +vt 0.5792 0.7816 +vt 0.6064 0.8083 +vt 0.5836 0.8800 +vt 0.6267 0.8356 +vt 0.5922 0.7456 +vt 0.6489 0.7845 +vt 0.6185 0.7741 +vt 0.5626 0.8655 +vt 0.6504 0.8468 +vt 0.6790 0.8312 +vt 0.6761 0.7906 +vt 0.6655 0.8583 +vt 0.6118 0.9048 +vt 0.6943 0.7992 +vt 0.6481 0.7156 +vt 0.6324 0.7432 +vt 0.6639 0.6908 +vt 0.6678 0.7429 +vt 0.6794 0.7174 +vt 0.6863 0.7646 +vt 0.7003 0.7390 +vt 0.6278 0.6882 +vt 0.6478 0.6667 +vt 0.6084 0.7142 +vt 0.6530 0.8880 +vt 0.6928 0.8428 +vt 0.7131 0.8039 +vt 0.7020 0.8150 +vt 0.6823 0.8681 +vt 0.6959 0.8446 +vt 0.6881 0.8390 +vt 0.6747 0.8645 +vt 0.6760 0.8801 +vt 0.5909 0.5709 +vt 0.5772 0.5833 +vt 0.5978 0.6032 +vt 0.6001 0.6226 +vt 0.5668 0.6093 +vt 0.6145 0.6031 +vt 0.7148 0.8055 +vt 0.7211 0.7948 +vt 0.6719 0.3117 +vt 0.6516 0.3204 +vt 0.6654 0.3176 +vt 0.6671 0.8938 +vt 0.6699 0.8938 +vt 0.6249 0.9581 +vt 0.6373 0.9613 +vt 0.6517 0.9246 +vt 0.6501 0.9776 +vt 0.6593 0.9226 +vt 0.6596 0.9235 +vt 0.6684 0.6255 +vt 0.6770 0.6096 +vt 0.6681 0.6094 +vt 0.6507 0.6159 +vt 0.6222 0.6342 +vt 0.6523 0.6367 +vt 0.6624 0.5737 +vt 0.6594 0.6036 +vt 0.6780 0.6682 +vt 0.6727 0.5830 +vt 0.6719 0.5637 +vt 0.6791 0.5736 +vt 0.6655 0.6490 +vt 0.6429 0.6108 +vt 0.6270 0.6059 +vt 0.6279 0.6212 +vt 0.5734 0.6238 +vt 0.5898 0.6425 +vt 0.6342 0.6028 +vt 0.6413 0.0031 +vt 0.6418 0.0438 +vt 0.6481 0.9988 +vt 0.6502 0.9610 +vt 0.6372 0.0884 +vt 0.6397 0.0794 +vt 0.6441 0.0381 +vt 0.6528 0.9591 +vt 0.6373 0.0937 +vt 0.7164 0.5925 +vt 0.6973 0.5842 +vt 0.6978 0.6406 +vt 0.6082 0.6639 +vt 0.5858 0.6847 +vt 0.6906 0.6913 +vt 0.6310 0.6489 +vt 0.5652 0.6566 +vt 0.6996 0.7741 +vt 0.6868 0.6070 +vt 0.5467 0.6316 +vt 0.5354 0.6064 +vt 0.3180 0.9920 +vt 0.3187 0.9774 +vt 0.3181 0.9837 +vt 0.3314 0.0170 +vt 0.3502 0.0379 +vt 0.3337 0.0165 +vt 0.3375 0.0204 +vt 0.3442 0.0285 +vt 0.3189 0.9925 +vt 0.3187 0.0004 +vt 0.3206 0.0057 +vt 0.3199 0.0009 +vt 0.3192 0.9936 +vt 0.3196 0.9797 +vt 0.7363 0.3913 +vt 0.7281 0.3940 +vt 0.7322 0.3948 +vt 0.7311 0.4057 +vt 0.7351 0.4165 +vt 0.7301 0.3685 +vt 0.7238 0.3673 +vt 0.3334 0.0020 +vt 0.3404 0.0217 +vt 0.3253 0.0093 +vt 0.4365 0.3393 +vt 0.4277 0.4025 +vt 0.4169 0.3801 +vt 0.4288 0.3233 +vt 0.3981 0.3938 +vt 0.4145 0.4437 +vt 0.4051 0.3262 +vt 0.4173 0.3214 +vt 0.4275 0.2585 +vt 0.4332 0.2655 +vt 0.4406 0.2661 +vt 0.4031 0.4752 +vt 0.3226 0.9947 +vt 0.3221 0.0060 +vt 0.3281 0.0034 +vt 0.7368 0.4174 +vt 0.7455 0.4408 +vt 0.7497 0.4610 +vt 0.7406 0.4381 +vt 0.7481 0.4518 +vt 0.7313 0.4159 +vt 0.7341 0.4197 +vt 0.7330 0.4137 +vt 0.7419 0.4313 +vt 0.7651 0.5456 +vt 0.7687 0.5740 +vt 0.7673 0.5360 +vt 0.7640 0.5229 +vt 0.7621 0.5238 +vt 0.7411 0.4364 +vt 0.7428 0.4346 +vt 0.7382 0.4256 +vt 0.7389 0.4250 +vt 0.7366 0.4226 +vt 0.7481 0.4556 +vt 0.7548 0.4697 +vt 0.7488 0.4571 +vt 0.7407 0.4378 +vt 0.7444 0.4444 +vt 0.7466 0.4454 +vt 0.7544 0.4642 +vt 0.7665 0.5203 +vt 0.7584 0.4756 +vt 0.7609 0.4931 +vt 0.7556 0.4741 +vt 0.7597 0.4877 +vt 0.7465 0.5526 +vt 0.7315 0.5711 +vt 0.7541 0.5889 +vt 0.7627 0.5496 +vt 0.7616 0.5805 +vt 0.3595 0.4130 +vt 0.3798 0.3511 +vt 0.3770 0.3474 +vt 0.3582 0.4015 +vt 0.3819 0.3497 +vt 0.3943 0.2814 +vt 0.3905 0.2768 +vt 0.3999 0.2862 +vt 0.3922 0.3471 +vt 0.3516 0.4544 +vt 0.3693 0.4207 +vt 0.3467 0.4611 +vt 0.3592 0.5045 +vt 0.3749 0.3377 +vt 0.4142 0.2881 +vt 0.6313 0.3866 +vt 0.6376 0.3916 +vt 0.6369 0.3831 +vt 0.6366 0.3973 +vt 0.6262 0.3945 +vt 0.6280 0.3866 +vt 0.6246 0.3931 +vt 0.6255 0.5966 +vt 0.6237 0.4001 +vt 0.6225 0.4016 +vt 0.6292 0.3819 +vt 0.6377 0.3744 +vt 0.6376 0.3752 +vt 0.6281 0.3999 +vt 0.3459 0.4398 +vt 0.3470 0.4265 +vt 0.3608 0.3750 +vt 0.3735 0.3126 +vt 0.4465 0.2756 +vt 0.3438 0.4447 +vt 0.3577 0.3918 +vt 0.3358 0.4869 +vt 0.4238 0.4113 +vt 0.4368 0.3446 +vt 0.4489 0.2825 +vt 0.3747 0.3237 +vt 0.3870 0.2681 +vt 0.3843 0.2579 +vt 0.3769 0.3122 +vt 0.3837 0.2494 +vt 0.3871 0.2421 +vt 0.6613 0.5348 +vt 0.6550 0.5283 +vt 0.6569 0.5415 +vt 0.6587 0.5538 +vt 0.6501 0.5215 +vt 0.6555 0.5602 +vt 0.6737 0.5087 +vt 0.6663 0.5229 +vt 0.6846 0.5262 +vt 0.6963 0.5252 +vt 0.6823 0.4959 +vt 0.6635 0.5086 +vt 0.6378 0.5866 +vt 0.6490 0.5966 +vt 0.7125 0.5197 +vt 0.7030 0.5072 +vt 0.7111 0.5522 +vt 0.7280 0.5244 +vt 0.7350 0.5981 +vt 0.6084 0.5676 +vt 0.5973 0.5526 +vt 0.5522 0.5618 +vt 0.6079 0.5474 +vt 0.6152 0.5585 +vt 0.6197 0.5503 +vt 0.6021 0.5456 +vt 0.5080 0.5843 +vt 0.5181 0.5942 +vt 0.5342 0.5648 +vt 0.5013 0.5785 +vt 0.5407 0.5580 +vt 0.6468 0.5332 +vt 0.6256 0.5354 +vt 0.6163 0.5342 +vt 0.6127 0.5333 +vt 0.6253 0.5710 +vt 0.7229 0.3724 +vt 0.7228 0.3887 +vt 0.7199 0.3665 +vt 0.7203 0.3942 +vt 0.7187 0.3751 +vt 0.7260 0.3554 +vt 0.7210 0.3543 +vt 0.7164 0.3618 +vt 0.7234 0.4168 +vt 0.7498 0.4599 +vt 0.7275 0.4073 +vt 0.7713 0.5719 +vt 0.6228 0.1850 +vt 0.6096 0.2664 +vt 0.6216 0.1816 +vt 0.7224 0.3432 +vt 0.7374 0.3911 +vt 0.7476 0.4464 +vt 0.7516 0.4790 +vt 0.7551 0.5034 +vt 0.7555 0.4909 +vt 0.7600 0.5282 +vt 0.7530 0.4704 +vt 0.7417 0.4991 +vt 0.7361 0.5256 +vt 0.7275 0.4927 +vt 0.7080 0.4688 +vt 0.7338 0.4938 +vt 0.7671 0.5827 +vt 0.7591 0.4994 +vt 0.5679 0.9490 +vt 0.5413 0.0076 +vt 0.5820 0.0068 +vt 0.5349 0.9227 +vt 0.5008 0.9672 +vt 0.5713 0.0850 +vt 0.5006 0.8860 +vt 0.5288 0.8320 +vt 0.5918 0.1017 +vt 0.6080 0.0540 +vt 0.6078 0.0018 +vt 0.6085 0.9513 +vt 0.4404 0.6998 +vt 0.4190 0.7372 +vt 0.4576 0.7621 +vt 0.4350 0.7766 +vt 0.4301 0.8270 +vt 0.4692 0.7246 +vt 0.5020 0.7554 +vt 0.5192 0.7178 +vt 0.4906 0.6887 +vt 0.4660 0.6649 +vt 0.4925 0.7955 +vt 0.4695 0.8439 +vt 0.4568 0.8703 +vt 0.4406 0.9511 +vt 0.4759 0.9141 +vt 0.6070 0.1046 +vt 0.6454 0.9620 +vt 0.6379 0.0468 +vt 0.6339 0.0043 +vt 0.6313 0.0500 +vt 0.6337 0.0926 +vt 0.6279 0.0972 +vt 0.6227 0.0044 +vt 0.6214 0.0531 +vt 0.6190 0.1021 +vt 0.4823 0.6173 +vt 0.4978 0.6327 +vt 0.4712 0.6077 +vt 0.3936 0.6730 +vt 0.3649 0.7131 +vt 0.3763 0.7130 +vt 0.3908 0.6726 +vt 0.3613 0.7147 +vt 0.4029 0.6765 +vt 0.4475 0.6492 +vt 0.4187 0.6850 +vt 0.4350 0.6400 +vt 0.4623 0.6012 +vt 0.4646 0.6026 +vt 0.4988 0.5766 +vt 0.4280 0.6355 +vt 0.4260 0.6344 +vt 0.5363 0.7892 +vt 0.5178 0.6555 +vt 0.5409 0.6833 +vt 0.5493 0.7500 +vt 0.5661 0.7143 +vt 0.3959 0.7191 +vt 0.7441 0.4425 +vt 0.6362 0.4250 +vt 0.6342 0.4392 +vt 0.6425 0.4319 +vt 0.6402 0.4102 +vt 0.6373 0.4111 +vt 0.6425 0.4465 +vt 0.6458 0.5078 +vt 0.6496 0.4885 +vt 0.6444 0.4758 +vt 0.6480 0.4694 +vt 0.6492 0.5095 +vt 0.6381 0.3994 +vt 0.6364 0.3480 +vt 0.6345 0.3617 +vt 0.6347 0.3788 +vt 0.6584 0.5193 +vt 0.6561 0.5046 +vt 0.6539 0.5168 +vt 0.6355 0.4533 +vt 0.6429 0.4649 +vt 0.6388 0.4759 +vt 0.6469 0.5192 +vt 0.6415 0.3356 +vt 0.7049 0.3330 +vt 0.7077 0.3320 +vt 0.7056 0.3301 +vt 0.7036 0.3249 +vt 0.7033 0.3208 +vt 0.7105 0.3319 +vt 0.7102 0.3243 +vt 0.7079 0.3385 +vt 0.6988 0.3036 +vt 0.6913 0.3006 +vt 0.6944 0.3038 +vt 0.6993 0.3120 +vt 0.7028 0.3125 +vt 0.6972 0.3078 +vt 0.7078 0.3245 +vt 0.7032 0.3286 +vt 0.7014 0.3208 +vt 0.7012 0.3251 +vt 0.7092 0.3145 +vt 0.7038 0.3066 +vt 0.6920 0.2988 +vt 0.7087 0.3120 +vt 0.6454 0.3279 +vt 0.6839 0.2990 +vt 0.6888 0.2985 +vt 0.6551 0.4350 +vt 0.6480 0.4551 +vt 0.6490 0.3312 +vt 0.6466 0.3396 +vt 0.6549 0.3362 +vt 0.6558 0.3283 +vt 0.7519 0.6745 +vt 0.7545 0.6750 +vt 0.7533 0.6681 +vt 0.7552 0.6705 +vt 0.7563 0.6691 +vt 0.7567 0.6703 +vt 0.6455 0.3484 +vt 0.6548 0.3450 +vt 0.6451 0.3682 +vt 0.6496 0.4021 +vt 0.6620 0.3968 +vt 0.6547 0.3796 +vt 0.6551 0.3664 +vt 0.6550 0.3550 +vt 0.7241 0.7361 +vt 0.7112 0.7563 +vt 0.7207 0.7549 +vt 0.7090 0.7784 +vt 0.7127 0.7861 +vt 0.7402 0.7122 +vt 0.7307 0.7081 +vt 0.7177 0.7270 +vt 0.7448 0.6964 +vt 0.7400 0.6931 +vt 0.7545 0.6673 +vt 0.7519 0.6801 +vt 0.7515 0.6901 +vt 0.7524 0.6783 +vt 0.7542 0.6767 +vt 0.7274 0.7640 +vt 0.7371 0.7306 +vt 0.6636 0.4942 +vt 0.6697 0.4801 +vt 0.6563 0.4817 +vt 0.6600 0.4572 +vt 0.6654 0.4186 +vt 0.6686 0.4406 +vt 0.6460 0.4176 +vt 0.3824 0.3179 +vt 0.3769 0.3122 +vt 0.3560 0.4442 +vt 0.3608 0.3750 +vt 0.3928 0.2716 +vt 0.5435 0.0892 +vt 0.5026 0.1315 +vt 0.5354 0.1581 +vt 0.3405 0.4217 +vt 0.3346 0.2326 +vt 0.3383 0.5642 +vt 0.5234 0.7442 +vt 0.5026 0.8959 +vt 0.5120 0.8606 +vt 0.5680 0.1305 +vt 0.4051 0.3262 +vt 0.3923 0.3254 +vt 0.3981 0.3938 +vt 0.3733 0.4608 +vt 0.4120 0.2838 +vt 0.4020 0.2824 +vt 0.4816 0.7134 +vt 0.4421 0.8883 +vt 0.4683 0.9130 +vt 0.3958 0.7953 +vt 0.3778 0.9996 +vt 0.4161 0.8583 +vt 0.4068 0.0374 +vt 0.4337 0.0564 +vt 0.7154 0.3301 +vt 0.3719 0.6156 +vt 0.3649 0.8174 +vt 0.3888 0.1168 +vt 0.4052 0.1315 +vt 0.5347 0.7140 +vt 0.5537 0.6023 +vt 0.5486 0.5943 +vt 0.5739 0.4747 +vt 0.4898 0.9193 +vt 0.4654 0.0813 +vt 0.5053 0.7473 +vt 0.4331 0.2895 +vt 0.4155 0.3587 +vt 0.4142 0.2881 +vt 0.3693 0.4207 +vt 0.3922 0.3471 +vt 0.4073 0.4337 +vt 0.3592 0.5045 +vt 0.3516 0.4544 +vt 0.3775 0.4983 +vt 0.4031 0.4752 +vt 0.4238 0.4113 +vt 0.3888 0.1168 +vt 0.3968 0.1769 +vt 0.3905 0.1716 +vt 0.4052 0.1315 +vt 0.4119 0.1885 +vt 0.4489 0.2825 +vt 0.4368 0.3446 +vt 0.4437 0.2860 +vt 0.3467 0.4972 +vt 0.3358 0.4869 +vt 0.3459 0.4398 +vt 0.4173 0.3214 +vt 0.4169 0.3801 +vt 0.3467 0.4611 +vt 0.6925 0.3050 +vt 0.6896 0.3084 +vt 0.6872 0.3040 +vt 0.6851 0.3069 +vt 0.6957 0.3074 +vt 0.6916 0.3124 +vt 0.6955 0.3122 +vt 0.6797 0.3077 +vt 0.6787 0.3016 +vt 0.6759 0.3053 +vt 0.6872 0.3131 +vt 0.6955 0.3191 +vt 0.6985 0.3156 +vt 0.6963 0.3129 +vt 0.6970 0.3210 +vt 0.6962 0.3292 +vt 0.6991 0.3199 +vt 0.6948 0.3269 +vt 0.6922 0.3215 +vt 0.6947 0.3347 +vt 0.6967 0.3320 +vt 0.6977 0.3393 +vt 0.6833 0.3163 +vt 0.6890 0.3188 +vt 0.7001 0.3349 +vt 0.6932 0.3273 +vt 0.7033 0.3412 +vt 0.6765 0.3094 +vt 0.6737 0.3141 +vt 0.7284 0.4173 +vt 0.7157 0.4868 +vt 0.7230 0.4820 +vt 0.7310 0.4461 +vt 0.7336 0.4421 +vt 0.7306 0.4312 +vt 0.7211 0.4746 +vt 0.7179 0.4627 +vt 0.7199 0.4460 +vt 0.7158 0.4360 +vt 0.7165 0.4270 +vt 0.7102 0.4333 +vt 0.7177 0.4153 +vt 0.7301 0.4599 +vt 0.7320 0.4718 +vt 0.7330 0.4570 +vt 0.7321 0.4559 +vt 0.7285 0.4532 +vt 0.7347 0.4617 +vt 0.7337 0.4773 +vt 0.7359 0.4707 +vt 0.7324 0.4783 +vt 0.7278 0.4412 +vt 0.7304 0.4516 +vt 0.7355 0.4318 +vt 0.7336 0.4311 +vt 0.7355 0.4424 +vt 0.7658 0.6221 +vt 0.7686 0.6129 +vt 0.7696 0.5947 +vt 0.7673 0.6138 +vt 0.7707 0.5971 +vt 0.7659 0.6339 +vt 0.7550 0.6871 +vt 0.7635 0.6447 +vt 0.7595 0.6494 +vt 0.7639 0.5966 +vt 0.7578 0.6013 +vt 0.7562 0.6171 +vt 0.7608 0.6181 +vt 0.7484 0.4884 +vt 0.7419 0.4832 +vt 0.7203 0.4342 +vt 0.7437 0.4738 +vt 0.7437 0.4530 +vt 0.7390 0.4633 +vt 0.7330 0.4846 +vt 0.7356 0.4771 +vt 0.7268 0.4674 +vt 0.7239 0.4562 +vt 0.7455 0.4508 +vt 0.7456 0.4432 +vt 0.7391 0.4682 +vt 0.7348 0.4246 +vt 0.7296 0.4226 +vt 0.7246 0.4280 +vt 0.7380 0.4477 +vt 0.7382 0.4509 +vt 0.7233 0.4433 +vt 0.7580 0.6481 +vt 0.7495 0.6267 +vt 0.7488 0.6456 +vt 0.7481 0.6830 +vt 0.7450 0.6824 +vt 0.7456 0.6733 +vt 0.7577 0.6551 +vt 0.7542 0.6664 +vt 0.7522 0.6706 +vt 0.7495 0.6724 +vt 0.7521 0.6720 +vt 0.7504 0.6732 +vt 0.7460 0.6549 +vt 0.7422 0.6634 +vt 0.7468 0.6663 +vt 0.7364 0.6611 +vt 0.7370 0.6814 +vt 0.7505 0.6635 +vt 0.7478 0.6658 +vt 0.7286 0.6748 +vt 0.7290 0.6910 +vt 0.7489 0.6703 +vt 0.7119 0.7009 +vt 0.7211 0.6520 +vt 0.7071 0.6695 +vt 0.7131 0.6296 +vt 0.7388 0.6333 +vt 0.7488 0.6664 +vt 0.7483 0.6074 +vt 0.7252 0.6211 +vt 0.7300 0.7680 +vt 0.7499 0.6909 +vt 0.7532 0.6216 +vt 0.7535 0.6043 +vt 0.7403 0.7403 +vt 0.7584 0.6345 +vt 0.7594 0.6455 +vt 0.7583 0.6763 +vt 0.7396 0.7460 +vt 0.3752 0.9718 +vt 0.3720 0.0046 +vt 0.3818 0.9952 +vt 0.3905 0.0174 +vt 0.3800 0.0298 +vt 0.3859 0.0394 +vt 0.3929 0.0269 +vt 0.3850 0.0173 +vt 0.3981 0.0034 +vt 0.3943 0.0248 +vt 0.3932 0.9906 +vt 0.3521 0.9302 +vt 0.3788 0.9840 +vt 0.3609 0.9259 +vt 0.3895 0.0117 +vt 0.3588 0.9074 +vt 0.3655 0.9149 +vt 0.3812 0.9834 +vt 0.3485 0.9609 +vt 0.3740 0.9192 +vt 0.3779 0.8863 +vt 0.3657 0.8976 +vt 0.3614 0.9343 +vt 0.3651 0.9233 +vt 0.3626 0.9164 +vt 0.3531 0.9221 +vt 0.3678 0.9144 +vt 0.3835 0.8972 +vt 0.3688 0.9370 +vt 0.3542 0.9507 +vt 0.3904 0.9613 +vt 0.3870 0.9228 +vt 0.3924 0.0217 +vt 0.3957 0.0318 +vt 0.3950 0.0264 +vt 0.3771 0.9590 +vt 0.3755 0.9272 +vt 0.3857 0.9191 +vt 0.3941 0.9065 +vt 0.3989 0.9320 +vt 0.4019 0.0738 +vt 0.3968 0.0491 +vt 0.4066 0.0958 +vt 0.3860 0.9570 +vt 0.3889 0.9893 +vt 0.3917 0.0136 +vt 0.3947 0.0053 +vt 0.3940 0.0323 +vt 0.3843 0.9891 +vt 0.4093 0.1084 +vt 0.4037 0.9939 +vt 0.4056 0.0608 +vt 0.3985 0.9799 +vt 0.4019 0.1099 +vt 0.4095 0.1570 +vt 0.3984 0.0550 +vt 0.3965 0.0412 +vt 0.3569 0.9031 +vt 0.3543 0.8903 +vt 0.3501 0.8649 +vt 0.3721 0.8949 +vt 0.3435 0.8856 +vt 0.3460 0.8779 +vt 0.3479 0.8870 +vt 0.3447 0.8689 +vt 0.3475 0.9007 +vt 0.3434 0.9022 +vt 0.3428 0.9186 +vt 0.3401 0.8863 +vt 0.3418 0.8711 +vt 0.3501 0.8527 +vt 0.3445 0.8622 +vt 0.3516 0.8491 +vt 0.3456 0.8589 +vt 0.3389 0.9046 +vt 0.3256 0.9433 +vt 0.3307 0.9336 +vt 0.3283 0.9542 +vt 0.3321 0.9671 +vt 0.3669 0.0061 +vt 0.3561 0.0176 +vt 0.3313 0.9869 +vt 0.3429 0.0085 +vt 0.3235 0.9614 +vt 0.3369 0.9254 +vt 0.3336 0.9120 +vt 0.3533 0.8522 +vt 0.3528 0.8665 +vt 0.3640 0.8699 +vt 0.3753 0.8464 +vt 0.3547 0.8843 +vt 0.3474 0.8854 +vt 0.3434 0.8798 +vt 0.3444 0.8972 +vt 0.3405 0.8917 +vt 0.3490 0.9055 +vt 0.3371 0.8920 +vt 0.3380 0.8897 +vt 0.3407 0.8779 +vt 0.3992 0.0233 +vt 0.5352 0.5926 +vt 0.4781 0.0534 +vt 0.5587 0.4742 +vt 0.5206 0.5730 +vt 0.4794 0.0534 +vt 0.3445 0.9289 +vt 0.3435 0.0559 +vt 0.3613 0.0095 +vt 0.3618 0.9304 +vt 0.3355 0.0168 +vt 0.3371 0.9315 +vt 0.4831 0.0333 +vt 0.3825 0.8840 +vt 0.3820 0.9469 +vt 0.5201 0.4250 +vt 0.4968 0.5519 +vt 0.5429 0.4553 +vt 0.4896 0.3625 +vt 0.4674 0.4825 +vt 0.4508 0.6882 +vt 0.3988 0.9140 +vt 0.3993 0.8765 +vt 0.3855 0.8798 +vt 0.3980 0.8521 +vt 0.3873 0.8563 +vt 0.3901 0.8353 +vt 0.4011 0.8795 +vt 0.3608 0.8647 +vt 0.3739 0.8600 +vt 0.4045 0.8808 +vt 0.4034 0.9357 +vt 0.3599 0.8479 +vt 0.3439 0.8625 +vt 0.4027 0.9078 +vt 0.3591 0.1458 +vt 0.3609 0.0596 +vt 0.3427 0.1201 +vt 0.3430 0.1679 +vt 0.3352 0.1093 +vt 0.3581 0.2283 +vt 0.3808 0.2049 +vt 0.3425 0.2595 +vt 0.3557 0.3879 +vt 0.3564 0.5892 +vt 0.3453 0.6031 +vt 0.3500 0.8297 +vt 0.3825 0.1260 +vt 0.4018 0.3384 +vt 0.4276 0.4023 +vt 0.4344 0.2296 +vt 0.4261 0.6342 +vt 0.3965 0.6072 +vt 0.4575 0.2828 +vt 0.3631 0.0005 +vt 0.3561 0.0021 +vt 0.3744 0.3639 +vt 0.3450 0.8412 +vt 0.3524 0.0055 +vt 0.4586 0.1835 +vt 0.4538 0.2283 +vt 0.4499 0.2232 +vt 0.4568 0.1826 +vt 0.4550 0.2312 +vt 0.4586 0.1873 +vt 0.4656 0.1353 +vt 0.4658 0.1332 +vt 0.4647 0.1289 +vt 0.4541 0.1814 +vt 0.4490 0.1902 +vt 0.4513 0.2364 +vt 0.4398 0.1309 +vt 0.4430 0.2404 +vt 0.4276 0.2379 +vt 0.4331 0.2895 +vt 0.4197 0.1405 +vt 0.4119 0.1885 +vt 0.4437 0.2860 +vt 0.3888 0.2151 +vt 0.3844 0.2079 +vt 0.3941 0.2221 +vt 0.3822 0.2012 +vt 0.3785 0.1601 +vt 0.3842 0.1636 +vt 0.3905 0.1716 +vt 0.3713 0.1558 +vt 0.3740 0.1571 +vt 0.3638 0.1013 +vt 0.3689 0.1037 +vt 0.3616 0.1007 +vt 0.4444 0.2224 +vt 0.4474 0.1973 +vt 0.3809 0.1981 +vt 0.3560 0.4442 +vt 0.3733 0.4608 +vt 0.3775 0.4983 +vt 0.3467 0.4972 +vt 0.4073 0.4337 +vt 0.3923 0.3254 +vt 0.3824 0.3179 +vt 0.4155 0.3587 +vt 0.4063 0.2359 +vt 0.3995 0.2270 +vt 0.3968 0.1769 +vt 0.3396 0.9119 +vt 0.3338 0.9056 +vt 0.3361 0.9072 +vt 0.3288 0.9244 +vt 0.3206 0.9618 +vt 0.3255 0.9386 +vt 0.3313 0.9241 +vt 0.3297 0.9430 +vt 0.3239 0.9526 +vt 0.3359 0.9550 +vt 0.3381 0.9340 +vt 0.3211 0.9601 +vt 0.3223 0.9781 +vt 0.3601 0.0186 +vt 0.3621 0.0376 +vt 0.3487 0.0173 +vt 0.3381 0.9875 +vt 0.3701 0.0309 +vt 0.3486 0.0264 +vt 0.3547 0.0334 +vt 0.3443 0.9480 +vt 0.3405 0.9684 +vt 0.3283 0.9615 +vt 0.3333 0.9741 +vt 0.3194 0.9729 +vt 0.3562 0.0335 +vt 0.3758 0.1070 +vt 0.3312 0.0127 +vt 0.3222 0.9924 +vt 0.3235 0.0033 +vt 0.3262 0.9897 +vt 0.3334 0.0034 +vt 0.7159 0.3759 +vt 0.7141 0.4094 +vt 0.7173 0.4000 +vt 0.7120 0.3951 +vt 0.6954 0.4920 +vt 0.6880 0.4796 +vt 0.6863 0.4537 +vt 0.6983 0.4607 +vt 0.6983 0.4196 +vt 0.6975 0.4733 +vt 0.7081 0.3698 +vt 0.6985 0.3552 +vt 0.7004 0.3661 +vt 0.7064 0.3606 +vt 0.7012 0.3536 +vt 0.7052 0.3745 +vt 0.7012 0.3795 +vt 0.7160 0.3450 +vt 0.7009 0.3965 +vt 0.6216 0.5083 +vt 0.6146 0.4661 +vt 0.6141 0.4795 +vt 0.6388 0.5111 +vt 0.6308 0.4719 +vt 0.6129 0.4562 +vt 0.6204 0.4759 +vt 0.6279 0.5025 +vt 0.6176 0.4615 +vt 0.6312 0.5200 +vt 0.6393 0.5252 +vt 0.6180 0.5091 +vt 0.6212 0.5220 +vt 0.6735 0.4585 +vt 0.6242 0.4453 +vt 0.6218 0.4601 +vt 0.6809 0.4374 +vt 0.6890 0.4097 +vt 0.6766 0.3971 +vt 0.6815 0.3770 +vt 0.6864 0.3751 +vt 0.6850 0.3931 +vt 0.6915 0.3725 +vt 0.6765 0.3780 +vt 0.6712 0.3785 +vt 0.6723 0.3631 +vt 0.6652 0.3644 +vt 0.6963 0.3844 +vt 0.6173 0.4495 +vt 0.6149 0.4502 +vt 0.6166 0.4400 +vt 0.6198 0.4299 +vt 0.6205 0.4480 +vt 0.6242 0.4276 +vt 0.6290 0.4182 +vt 0.6252 0.4135 +vt 0.7186 0.3373 +vt 0.7170 0.3376 +vt 0.6202 0.4214 +vt 0.6293 0.4400 +vt 0.6286 0.4293 +vt 0.5150 0.2232 +vt 0.5514 0.2253 +vt 0.5886 0.1474 +vt 0.6027 0.1516 +vt 0.5650 0.1679 +vt 0.5143 0.0377 +vt 0.5914 0.2200 +vt 0.5831 0.1889 +vt 0.5700 0.2500 +vt 0.4559 0.9748 +vt 0.4710 0.0224 +vt 0.4579 0.0364 +vt 0.4328 0.0107 +vt 0.4157 0.8166 +vt 0.4071 0.8471 +vt 0.4300 0.8743 +vt 0.4274 0.9790 +vt 0.4680 0.1094 +vt 0.6046 0.2813 +vt 0.6183 0.1957 +vt 0.6066 0.2409 +vt 0.5912 0.2878 +vt 0.6306 0.1342 +vt 0.6218 0.1450 +vt 0.6067 0.1967 +vt 0.6273 0.1396 +vt 0.6152 0.2285 +vt 0.6137 0.1498 +vt 0.6083 0.2615 +vt 0.3597 0.7971 +vt 0.3450 0.8101 +vt 0.3373 0.8710 +vt 0.3393 0.8180 +vt 0.3505 0.7597 +vt 0.3458 0.7646 +vt 0.3635 0.7527 +vt 0.3845 0.7520 +vt 0.3811 0.7898 +vt 0.4031 0.7573 +vt 0.6173 0.5200 +vt 0.3997 0.7953 +vt 0.4062 0.7959 +vt 0.4110 0.8021 +vt 0.4095 0.7686 +vt 0.4055 0.8092 +vt 0.4057 0.8167 +vt 0.4046 0.8407 +vt 0.4252 0.7777 +vt 0.4289 0.9365 +vt 0.4269 0.0837 +vt 0.4252 0.1234 +vt 0.4550 0.1371 +vt 0.4282 0.0391 +vt 0.4154 0.0556 +vt 0.4122 0.0879 +vt 0.4430 0.1591 +vt 0.4666 0.2091 +vt 0.4857 0.1688 +vt 0.4037 0.0205 +vt 0.4173 0.0203 +vt 0.3973 0.0234 +vt 0.4125 0.9787 +vt 0.5741 0.3915 +vt 0.5598 0.3803 +vt 0.5737 0.3149 +vt 0.5934 0.3267 +vt 0.5170 0.3236 +vt 0.5432 0.3530 +vt 0.5841 0.3906 +vt 0.6020 0.3167 +vt 0.5998 0.3370 +vt 0.5923 0.3712 +vt 0.4909 0.2674 +vt 0.3643 0.8387 +vt 0.3981 0.8175 +vt 0.3630 0.8415 +vt 0.3609 0.8516 +vt 0.4153 0.9429 +vt 0.4136 0.9023 +vt 0.3988 0.9095 +vt 0.3934 0.8712 +vt 0.3813 0.8286 +vt 0.3893 0.8504 +vt 0.4001 0.9380 +vt 0.3991 0.9787 +vt 0.3766 0.8689 +vt 0.6240 0.4069 +vt 0.6221 0.4137 +vt 0.6296 0.4067 +vt 0.7137 0.3228 +vt 0.6650 0.3523 +vt 0.6838 0.3379 +vt 0.6796 0.3295 +vt 0.6766 0.3388 +vt 0.6643 0.3419 +vt 0.6713 0.3400 +vt 0.6699 0.3312 +vt 0.6634 0.3332 +vt 0.6810 0.3234 +vt 0.6874 0.3313 +vt 0.6963 0.3466 +vt 0.7011 0.3465 +vt 0.6913 0.3591 +vt 0.6868 0.3606 +vt 0.7105 0.3496 +vt 0.6823 0.3208 +vt 0.6628 0.3259 +vt 0.6570 0.3222 +vt 0.6744 0.3183 +vt 0.6730 0.3233 +vt 0.5984 0.3361 +vt 0.5772 0.4729 +vt 0.6776 0.3623 +vt 0.6822 0.3488 +vt 0.6775 0.3494 +vt 0.6722 0.3505 +vt 0.6684 0.3243 +vt 0.6823 0.3617 +vt 0.6214 0.0531 +vt 0.6190 0.1021 +vt 0.6080 0.0540 +vt 0.6227 0.0044 +vt 0.6078 0.0018 +vt 0.6313 0.0500 +vt 0.6279 0.0972 +vt 0.6070 0.1046 +vt 0.6249 0.9581 +vt 0.6339 0.0043 +vt 0.6373 0.9613 +vt 0.6454 0.9620 +vt 0.6413 0.0031 +vt 0.6379 0.0468 +vt 0.6418 0.0438 +vt 0.6502 0.9610 +vt 0.6517 0.9246 +vt 0.6504 0.8468 +vt 0.6530 0.8880 +vt 0.6267 0.8356 +vt 0.5626 0.8655 +vt 0.5836 0.8800 +vt 0.5679 0.9490 +vt 0.6085 0.9513 +vt 0.6118 0.9048 +vt 0.5820 0.0068 +vt 0.5349 0.9227 +vt 0.5413 0.0076 +vt 0.5008 0.9672 +vt 0.5713 0.0850 +vt 0.6671 0.8938 +vt 0.5918 0.1017 +vt 0.6397 0.0794 +vt 0.6481 0.9988 +vt 0.6727 0.5830 +vt 0.6770 0.6096 +vt 0.6681 0.6094 +vt 0.6624 0.5737 +vt 0.6719 0.5637 +vt 0.6791 0.5736 +vt 0.6928 0.8428 +vt 0.7148 0.8055 +vt 0.6699 0.8938 +vt 0.6596 0.9235 +vt 0.6973 0.5842 +vt 0.7164 0.5925 +vt 0.6978 0.6406 +vt 0.6429 0.6108 +vt 0.6594 0.6036 +vt 0.6507 0.6159 +vt 0.6523 0.6367 +vt 0.6684 0.6255 +vt 0.6279 0.6212 +vt 0.6222 0.6342 +vt 0.6780 0.6682 +vt 0.6655 0.6490 +vt 0.6528 0.9591 +vt 0.6337 0.0926 +vt 0.6372 0.0884 +vt 0.5493 0.7500 +vt 0.5661 0.7143 +vt 0.5792 0.7816 +vt 0.5922 0.7456 +vt 0.6084 0.7142 +vt 0.5858 0.6847 +vt 0.3763 0.7130 +vt 0.4029 0.6765 +vt 0.3959 0.7191 +vt 0.4187 0.6850 +vt 0.4190 0.7372 +vt 0.4404 0.6998 +vt 0.4906 0.6887 +vt 0.5178 0.6555 +vt 0.5192 0.7178 +vt 0.5409 0.6833 +vt 0.5652 0.6566 +vt 0.5467 0.6316 +vt 0.4475 0.6492 +vt 0.4350 0.6400 +vt 0.4823 0.6173 +vt 0.5181 0.5942 +vt 0.4978 0.6327 +vt 0.3649 0.7131 +vt 0.3936 0.6730 +vt 0.4712 0.6077 +vt 0.5080 0.5843 +vt 0.5354 0.6064 +vt 0.4280 0.6355 +vt 0.4660 0.6649 +vt 0.4925 0.7955 +vt 0.5288 0.8320 +vt 0.5006 0.8860 +vt 0.4695 0.8439 +vt 0.4759 0.9141 +vt 0.4576 0.7621 +vt 0.4692 0.7246 +vt 0.4350 0.7766 +vt 0.4301 0.8270 +vt 0.4568 0.8703 +vt 0.4406 0.9511 +vt 0.5363 0.7892 +vt 0.5688 0.8211 +vt 0.5020 0.7554 +vt 0.6270 0.6059 +vt 0.6342 0.6028 +vt 0.6823 0.8681 +vt 0.6747 0.8645 +vt 0.6881 0.8390 +vt 0.7131 0.8039 +vt 0.7020 0.8150 +vt 0.6655 0.8583 +vt 0.6790 0.8312 +vt 0.5978 0.6032 +vt 0.5909 0.5709 +vt 0.6145 0.6031 +vt 0.6001 0.6226 +vt 0.5668 0.6093 +vt 0.5772 0.5833 +vt 0.6654 0.3176 +vt 0.6943 0.7992 +vt 0.6255 0.5966 +vt 0.3819 0.3497 +vt 0.3595 0.4130 +vt 0.3798 0.3511 +vt 0.3770 0.3474 +vt 0.3582 0.4015 +vt 0.3999 0.2862 +vt 0.3749 0.3377 +vt 0.3747 0.3237 +vt 0.3870 0.2681 +vt 0.3905 0.2768 +vt 0.3577 0.3918 +vt 0.3843 0.2579 +vt 0.6366 0.3973 +vt 0.6281 0.3999 +vt 0.6262 0.3945 +vt 0.6237 0.4001 +vt 0.6246 0.3931 +vt 0.6369 0.3831 +vt 0.6313 0.3866 +vt 0.6376 0.3752 +vt 0.6280 0.3866 +vt 0.6376 0.3916 +vt 0.3943 0.2814 +vt 0.5898 0.6425 +vt 0.6082 0.6639 +vt 0.6278 0.6882 +vt 0.6478 0.6667 +vt 0.6310 0.6489 +vt 0.6639 0.6908 +vt 0.6868 0.6070 +vt 0.6863 0.7646 +vt 0.6996 0.7741 +vt 0.6906 0.6913 +vt 0.6794 0.7174 +vt 0.7003 0.7390 +vt 0.5734 0.6238 +vt 0.6761 0.7906 +vt 0.6064 0.8083 +vt 0.5964 0.8460 +vt 0.6185 0.7741 +vt 0.6489 0.7845 +vt 0.6481 0.7156 +vt 0.6678 0.7429 +vt 0.6324 0.7432 +vt 0.5514 0.2253 +vt 0.5354 0.1581 +vt 0.5650 0.1679 +vt 0.5680 0.1305 +vt 0.5150 0.2232 +vt 0.5026 0.1315 +vt 0.5435 0.0892 +vt 0.5143 0.0377 +vt 0.5831 0.1889 +vt 0.5886 0.1474 +vt 0.5914 0.2200 +vt 0.6027 0.1516 +vt 0.4710 0.0224 +vt 0.4680 0.1094 +vt 0.4300 0.8743 +vt 0.4071 0.8471 +vt 0.4157 0.8166 +vt 0.4328 0.0107 +vt 0.4559 0.9748 +vt 0.4579 0.0364 +vt 0.4274 0.9790 +vt 0.4289 0.9365 +vt 0.5700 0.2500 +vt 0.6306 0.1342 +vt 0.6046 0.2813 +vt 0.5912 0.2878 +vt 0.6066 0.2409 +vt 0.6228 0.1850 +vt 0.6137 0.1498 +vt 0.6218 0.1450 +vt 0.6067 0.1967 +vt 0.6152 0.2285 +vt 0.6183 0.1957 +vt 0.6096 0.2664 +vt 0.7301 0.3685 +vt 0.6273 0.1396 +vt 0.3505 0.7597 +vt 0.3450 0.8101 +vt 0.6216 0.5083 +vt 0.6212 0.5220 +vt 0.3635 0.7527 +vt 0.3439 0.8625 +vt 0.3445 0.9289 +vt 0.3597 0.7971 +vt 0.3599 0.8479 +vt 0.6393 0.5252 +vt 0.6468 0.5332 +vt 0.6312 0.5200 +vt 0.6501 0.5215 +vt 0.6555 0.5602 +vt 0.6256 0.5354 +vt 0.6388 0.5111 +vt 0.6279 0.5025 +vt 0.6204 0.4759 +vt 0.6308 0.4719 +vt 0.6163 0.5342 +vt 0.6469 0.5192 +vt 0.6458 0.5078 +vt 0.3845 0.7520 +vt 0.4031 0.7573 +vt 0.4095 0.7686 +vt 0.3997 0.7953 +vt 0.4062 0.7959 +vt 0.4057 0.8167 +vt 0.4110 0.8021 +vt 0.4252 0.7777 +vt 0.3941 0.9065 +vt 0.3989 0.9320 +vt 0.4011 0.8795 +vt 0.4046 0.8407 +vt 0.3980 0.8521 +vt 0.4055 0.8092 +vt 0.4045 0.8808 +vt 0.3811 0.7898 +vt 0.3825 0.8840 +vt 0.3993 0.8765 +vt 0.3618 0.9304 +vt 0.7687 0.5740 +vt 0.7673 0.5360 +vt 0.6378 0.5866 +vt 0.6490 0.5966 +vt 0.6569 0.5415 +vt 0.6587 0.5538 +vt 0.6079 0.5474 +vt 0.6197 0.5503 +vt 0.6253 0.5710 +vt 0.6663 0.5229 +vt 0.6613 0.5348 +vt 0.6737 0.5087 +vt 0.6846 0.5262 +vt 0.7111 0.5522 +vt 0.6963 0.5252 +vt 0.6550 0.5283 +vt 0.6635 0.5086 +vt 0.6823 0.4959 +vt 0.6084 0.5676 +vt 0.5013 0.5785 +vt 0.5342 0.5648 +vt 0.4646 0.6026 +vt 0.5522 0.5618 +vt 0.6152 0.5585 +vt 0.5973 0.5526 +vt 0.7229 0.3724 +vt 0.7275 0.4073 +vt 0.7228 0.3887 +vt 0.7281 0.3940 +vt 0.7481 0.4556 +vt 0.7556 0.4741 +vt 0.7498 0.4599 +vt 0.7311 0.4057 +vt 0.7238 0.3673 +vt 0.7363 0.3913 +vt 0.7199 0.3665 +vt 0.7234 0.4168 +vt 0.7203 0.3942 +vt 0.7597 0.4877 +vt 0.7530 0.4704 +vt 0.7497 0.4610 +vt 0.7406 0.4381 +vt 0.7351 0.4165 +vt 0.7330 0.4137 +vt 0.7548 0.4697 +vt 0.7640 0.5229 +vt 0.7544 0.4642 +vt 0.7466 0.4454 +vt 0.7609 0.4931 +vt 0.7187 0.3751 +vt 0.7260 0.3554 +vt 0.7210 0.3543 +vt 0.7164 0.3618 +vt 0.7616 0.5805 +vt 0.7627 0.5496 +vt 0.7671 0.5827 +vt 0.7030 0.5072 +vt 0.7080 0.4688 +vt 0.7125 0.5197 +vt 0.7280 0.5244 +vt 0.7275 0.4927 +vt 0.7315 0.5711 +vt 0.7361 0.5256 +vt 0.7465 0.5526 +vt 0.7551 0.5034 +vt 0.7600 0.5282 +vt 0.7417 0.4991 +vt 0.7338 0.4938 +vt 0.7350 0.5981 +vt 0.7555 0.4909 +vt 0.7591 0.4994 +vt 0.7621 0.5238 +vt 0.7651 0.5456 +vt 0.7516 0.4790 +vt 0.6550 0.3550 +vt 0.6451 0.3682 +vt 0.6548 0.3450 +vt 0.6551 0.3664 +vt 0.6364 0.3480 +vt 0.6455 0.3484 +vt 0.6345 0.3617 +vt 0.6558 0.3283 +vt 0.6549 0.3362 +vt 0.6466 0.3396 +vt 0.6490 0.3312 +vt 0.6620 0.3968 +vt 0.6496 0.4021 +vt 0.6547 0.3796 +vt 0.6600 0.4572 +vt 0.6551 0.4350 +vt 0.6654 0.4186 +vt 0.6686 0.4406 +vt 0.6347 0.3788 +vt 0.6415 0.3356 +vt 0.7448 0.6964 +vt 0.7519 0.6801 +vt 0.7402 0.7122 +vt 0.7545 0.6673 +vt 0.7515 0.6901 +vt 0.7371 0.7306 +vt 0.7274 0.7640 +vt 0.7207 0.7549 +vt 0.7112 0.7563 +vt 0.7241 0.7361 +vt 0.7090 0.7784 +vt 0.7127 0.7861 +vt 0.7533 0.6681 +vt 0.7552 0.6705 +vt 0.7563 0.6691 +vt 0.7545 0.6750 +vt 0.7519 0.6745 +vt 0.6454 0.3279 +vt 0.7567 0.6703 +vt 0.7524 0.6783 +vt 0.7542 0.6767 +vt 0.6425 0.4465 +vt 0.6480 0.4694 +vt 0.6429 0.4649 +vt 0.6342 0.4392 +vt 0.6480 0.4551 +vt 0.6444 0.4758 +vt 0.6563 0.4817 +vt 0.6496 0.4885 +vt 0.6584 0.5193 +vt 0.6561 0.5046 +vt 0.6539 0.5168 +vt 0.6388 0.4759 +vt 0.6355 0.4533 +vt 0.6402 0.4102 +vt 0.6460 0.4176 +vt 0.6425 0.4319 +vt 0.6381 0.3994 +vt 0.6492 0.5095 +vt 0.6697 0.4801 +vt 0.6636 0.4942 +vt 0.7450 0.6824 +vt 0.7481 0.6830 +vt 0.7456 0.6733 +vt 0.7542 0.6664 +vt 0.7522 0.6706 +vt 0.7504 0.6732 +vt 0.7521 0.6720 +vt 0.7495 0.6724 +vt 0.7580 0.6481 +vt 0.7577 0.6551 +vt 0.7400 0.6931 +vt 0.7468 0.6663 +vt 0.7460 0.6549 +vt 0.7478 0.6658 +vt 0.7488 0.6456 +vt 0.7422 0.6634 +vt 0.7489 0.6703 +vt 0.7505 0.6635 +vt 0.7290 0.6910 +vt 0.7370 0.6814 +vt 0.7307 0.7081 +vt 0.7364 0.6611 +vt 0.7286 0.6748 +vt 0.7211 0.6520 +vt 0.7119 0.7009 +vt 0.7071 0.6695 +vt 0.7177 0.7270 +vt 0.7388 0.6333 +vt 0.7131 0.6296 +vt 0.7488 0.6664 +vt 0.7578 0.6013 +vt 0.7541 0.5889 +vt 0.7483 0.6074 +vt 0.6890 0.3188 +vt 0.6922 0.3215 +vt 0.6932 0.3273 +vt 0.6916 0.3124 +vt 0.6872 0.3131 +vt 0.6797 0.3077 +vt 0.6851 0.3069 +vt 0.6833 0.3163 +vt 0.6737 0.3141 +vt 0.6765 0.3094 +vt 0.6948 0.3269 +vt 0.6947 0.3347 +vt 0.6970 0.3210 +vt 0.6962 0.3292 +vt 0.6991 0.3199 +vt 0.7014 0.3208 +vt 0.7012 0.3251 +vt 0.6955 0.3191 +vt 0.6896 0.3084 +vt 0.6944 0.3038 +vt 0.6925 0.3050 +vt 0.6913 0.3006 +vt 0.6972 0.3078 +vt 0.6957 0.3074 +vt 0.6872 0.3040 +vt 0.6955 0.3122 +vt 0.6888 0.2985 +vt 0.6967 0.3320 +vt 0.3778 0.9996 +vt 0.4068 0.0374 +vt 0.4683 0.9130 +vt 0.5053 0.7473 +vt 0.4898 0.9193 +vt 0.4654 0.0813 +vt 0.4421 0.8883 +vt 0.4816 0.7134 +vt 0.4337 0.0564 +vt 0.4161 0.8583 +vt 0.3958 0.7953 +vt 0.5026 0.8959 +vt 0.5234 0.7442 +vt 0.3405 0.4217 +vt 0.5486 0.5943 +vt 0.5739 0.4747 +vt 0.3649 0.8174 +vt 0.7032 0.3286 +vt 0.7001 0.3349 +vt 0.6977 0.3393 +vt 0.7105 0.3319 +vt 0.7102 0.3243 +vt 0.7154 0.3301 +vt 0.7033 0.3412 +vt 0.7049 0.3330 +vt 0.7079 0.3385 +vt 0.3719 0.6156 +vt 0.7092 0.3145 +vt 0.6988 0.3036 +vt 0.7078 0.3245 +vt 0.7028 0.3125 +vt 0.6373 0.4111 +vt 0.6362 0.4250 +vt 0.6985 0.3156 +vt 0.6963 0.3129 +vt 0.6993 0.3120 +vt 0.7033 0.3208 +vt 0.7036 0.3249 +vt 0.7056 0.3301 +vt 0.7077 0.3320 +vt 0.7584 0.6345 +vt 0.7562 0.6171 +vt 0.7481 0.4518 +vt 0.7456 0.4432 +vt 0.7455 0.4408 +vt 0.7428 0.4346 +vt 0.7455 0.4508 +vt 0.7437 0.4530 +vt 0.7441 0.4425 +vt 0.7419 0.4313 +vt 0.7382 0.4256 +vt 0.7411 0.4364 +vt 0.7419 0.4832 +vt 0.7391 0.4682 +vt 0.7437 0.4738 +vt 0.7390 0.4633 +vt 0.7356 0.4771 +vt 0.7359 0.4707 +vt 0.7366 0.4226 +vt 0.7341 0.4197 +vt 0.7389 0.4250 +vt 0.7313 0.4159 +vt 0.7278 0.4412 +vt 0.7233 0.4433 +vt 0.7203 0.4342 +vt 0.7199 0.4460 +vt 0.7306 0.4312 +vt 0.7246 0.4280 +vt 0.7239 0.4562 +vt 0.7211 0.4746 +vt 0.7179 0.4627 +vt 0.7348 0.4246 +vt 0.7296 0.4226 +vt 0.7284 0.4173 +vt 0.7336 0.4311 +vt 0.7355 0.4318 +vt 0.7285 0.4532 +vt 0.7337 0.4773 +vt 0.7330 0.4846 +vt 0.7324 0.4783 +vt 0.7301 0.4599 +vt 0.7268 0.4674 +vt 0.7230 0.4820 +vt 0.7320 0.4718 +vt 0.4277 0.4025 +vt 0.4145 0.4437 +vt 0.4288 0.3233 +vt 0.4332 0.2655 +vt 0.4465 0.2756 +vt 0.4365 0.3393 +vt 0.4406 0.2661 +vt 0.3735 0.3126 +vt 0.3837 0.2494 +vt 0.3438 0.4447 +vt 0.3470 0.4265 +vt 0.3189 0.9925 +vt 0.3199 0.0009 +vt 0.3187 0.0004 +vt 0.7368 0.4174 +vt 0.7322 0.3948 +vt 0.7407 0.4378 +vt 0.7488 0.4571 +vt 0.7444 0.4444 +vt 0.3337 0.0165 +vt 0.3404 0.0217 +vt 0.3502 0.0379 +vt 0.3192 0.9936 +vt 0.3180 0.9920 +vt 0.3187 0.9774 +vt 0.3226 0.9947 +vt 0.3206 0.0057 +vt 0.3281 0.0034 +vt 0.3221 0.0060 +vt 0.3375 0.0204 +vt 0.3314 0.0170 +vt 0.3442 0.0285 +vt 0.3253 0.0093 +vt 0.3334 0.0020 +vt 0.3196 0.9797 +vt 0.3181 0.9837 +vt 0.7252 0.6211 +vt 0.7495 0.6267 +vt 0.7639 0.5966 +vt 0.7673 0.6138 +vt 0.7608 0.6181 +vt 0.7658 0.6221 +vt 0.7595 0.6494 +vt 0.7686 0.6129 +vt 0.7696 0.5947 +vt 0.7532 0.6216 +vt 0.7535 0.6043 +vt 0.7594 0.6455 +vt 0.7499 0.6909 +vt 0.7635 0.6447 +vt 0.7403 0.7403 +vt 0.7300 0.7680 +vt 0.7550 0.6871 +vt 0.7321 0.4559 +vt 0.7304 0.4516 +vt 0.7310 0.4461 +vt 0.7330 0.4570 +vt 0.7347 0.4617 +vt 0.7157 0.4868 +vt 0.7336 0.4421 +vt 0.7355 0.4424 +vt 0.7382 0.4509 +vt 0.7380 0.4477 +vt 0.7484 0.4884 +vt 0.7158 0.4360 +vt 0.7165 0.4270 +vt 0.7177 0.4153 +vt 0.7102 0.4333 +vt 0.3779 0.8863 +vt 0.3740 0.9192 +vt 0.3657 0.8976 +vt 0.3651 0.9233 +vt 0.3614 0.9343 +vt 0.3626 0.9164 +vt 0.3531 0.9221 +vt 0.3678 0.9144 +vt 0.3688 0.9370 +vt 0.3904 0.9613 +vt 0.3870 0.9228 +vt 0.3752 0.9718 +vt 0.3542 0.9507 +vt 0.3818 0.9952 +vt 0.3835 0.8972 +vt 0.3474 0.8854 +vt 0.3434 0.8798 +vt 0.3547 0.8843 +vt 0.3528 0.8665 +vt 0.3569 0.9031 +vt 0.3490 0.9055 +vt 0.3444 0.8972 +vt 0.3533 0.8522 +vt 0.3640 0.8699 +vt 0.3753 0.8464 +vt 0.3588 0.9074 +vt 0.3609 0.9259 +vt 0.3655 0.9149 +vt 0.3957 0.0318 +vt 0.3924 0.0217 +vt 0.3950 0.0264 +vt 0.3895 0.0117 +vt 0.3812 0.9834 +vt 0.3788 0.9840 +vt 0.3521 0.9302 +vt 0.3850 0.0173 +vt 0.3929 0.0269 +vt 0.3771 0.9590 +vt 0.3843 0.9891 +vt 0.3889 0.9893 +vt 0.3917 0.0136 +vt 0.3943 0.0248 +vt 0.3932 0.9906 +vt 0.3981 0.0034 +vt 0.3905 0.0174 +vt 0.3859 0.0394 +vt 0.3485 0.9609 +vt 0.3720 0.0046 +vt 0.3800 0.0298 +vt 0.3475 0.9007 +vt 0.3434 0.9022 +vt 0.3428 0.9186 +vt 0.3447 0.8689 +vt 0.3460 0.8779 +vt 0.3501 0.8649 +vt 0.3543 0.8903 +vt 0.3479 0.8870 +vt 0.3435 0.8856 +vt 0.3401 0.8863 +vt 0.3418 0.8711 +vt 0.3721 0.8949 +vt 0.3283 0.9542 +vt 0.3235 0.9614 +vt 0.3321 0.9671 +vt 0.3561 0.0176 +vt 0.3669 0.0061 +vt 0.3547 0.0334 +vt 0.3621 0.0376 +vt 0.3313 0.9869 +vt 0.3429 0.0085 +vt 0.3389 0.9046 +vt 0.3336 0.9120 +vt 0.3369 0.9254 +vt 0.3307 0.9336 +vt 0.3256 0.9433 +vt 0.3456 0.8589 +vt 0.3380 0.8897 +vt 0.3371 0.8920 +vt 0.3407 0.8779 +vt 0.3516 0.8491 +vt 0.3405 0.8917 +vt 0.3445 0.8622 +vt 0.3501 0.8527 +vt 0.3744 0.3639 +vt 0.3965 0.6072 +vt 0.3564 0.5892 +vt 0.3557 0.3879 +vt 0.4018 0.3384 +vt 0.4276 0.4023 +vt 0.4344 0.2296 +vt 0.4095 0.1570 +vt 0.4261 0.6342 +vt 0.3631 0.0005 +vt 0.4575 0.2828 +vt 0.4674 0.4825 +vt 0.3808 0.2049 +vt 0.3581 0.2283 +vt 0.3500 0.8297 +vt 0.3453 0.6031 +vt 0.3561 0.0021 +vt 0.4968 0.5519 +vt 0.5206 0.5730 +vt 0.4508 0.6882 +vt 0.5201 0.4250 +vt 0.5429 0.4553 +vt 0.4896 0.3625 +vt 0.5352 0.5926 +vt 0.5587 0.4742 +vt 0.4056 0.0608 +vt 0.3947 0.0053 +vt 0.3968 0.0491 +vt 0.3985 0.9799 +vt 0.3860 0.9570 +vt 0.4019 0.0738 +vt 0.4066 0.0958 +vt 0.4093 0.1084 +vt 0.3984 0.0550 +vt 0.4019 0.1099 +vt 0.3992 0.0233 +vt 0.4037 0.9939 +vt 0.3857 0.9191 +vt 0.3940 0.0323 +vt 0.3965 0.0412 +vt 0.3755 0.9272 +vt 0.3430 0.1679 +vt 0.3427 0.1201 +vt 0.3591 0.1458 +vt 0.3609 0.0596 +vt 0.3425 0.2595 +vt 0.3825 0.1260 +vt 0.3435 0.0559 +vt 0.3613 0.0095 +vt 0.3820 0.9469 +vt 0.3486 0.0264 +vt 0.3888 0.2151 +vt 0.3844 0.2079 +vt 0.3842 0.1636 +vt 0.3785 0.1601 +vt 0.3822 0.2012 +vt 0.3740 0.1571 +vt 0.3941 0.2221 +vt 0.3638 0.1013 +vt 0.4541 0.1814 +vt 0.4444 0.2224 +vt 0.4568 0.1826 +vt 0.4499 0.2232 +vt 0.3312 0.0127 +vt 0.3758 0.1070 +vt 0.3222 0.9924 +vt 0.3235 0.0033 +vt 0.3239 0.9526 +vt 0.3211 0.9601 +vt 0.3283 0.9615 +vt 0.3297 0.9430 +vt 0.3255 0.9386 +vt 0.3689 0.1037 +vt 0.4658 0.1332 +vt 0.4513 0.2364 +vt 0.4430 0.2404 +vt 0.4490 0.1902 +vt 0.4276 0.2379 +vt 0.4398 0.1309 +vt 0.4063 0.2359 +vt 0.4197 0.1405 +vt 0.4586 0.1873 +vt 0.3995 0.2270 +vt 0.4538 0.2283 +vt 0.4550 0.2312 +vt 0.4586 0.1835 +vt 0.4656 0.1353 +vt 0.4794 0.0534 +vt 0.4781 0.0534 +vt 0.3333 0.9741 +vt 0.3313 0.9241 +vt 0.3381 0.9340 +vt 0.3361 0.9072 +vt 0.3338 0.9056 +vt 0.3359 0.9550 +vt 0.3443 0.9480 +vt 0.3396 0.9119 +vt 0.3288 0.9244 +vt 0.3223 0.9781 +vt 0.3206 0.9618 +vt 0.3601 0.0186 +vt 0.3381 0.9875 +vt 0.3487 0.0173 +vt 0.3701 0.0309 +vt 0.3405 0.9684 +vt 0.3334 0.0034 +vt 0.3262 0.9897 +vt 0.3562 0.0335 +vt 0.3194 0.9729 +vt 0.7105 0.3496 +vt 0.7011 0.3465 +vt 0.7012 0.3536 +vt 0.7160 0.3450 +vt 0.6963 0.3466 +vt 0.6874 0.3313 +vt 0.7064 0.3606 +vt 0.7170 0.3376 +vt 0.6221 0.4137 +vt 0.6198 0.4299 +vt 0.7137 0.3228 +vt 0.7186 0.3373 +vt 0.6963 0.3844 +vt 0.7009 0.3965 +vt 0.6890 0.4097 +vt 0.7081 0.3698 +vt 0.7159 0.3759 +vt 0.7052 0.3745 +vt 0.7012 0.3795 +vt 0.7004 0.3661 +vt 0.6863 0.4537 +vt 0.6983 0.4196 +vt 0.6983 0.4607 +vt 0.7120 0.3951 +vt 0.6850 0.3931 +vt 0.6766 0.3971 +vt 0.6915 0.3725 +vt 0.6735 0.4585 +vt 0.6809 0.4374 +vt 0.6985 0.3552 +vt 0.6838 0.3379 +vt 0.6913 0.3591 +vt 0.6796 0.3295 +vt 0.6810 0.3234 +vt 0.6864 0.3751 +vt 0.6868 0.3606 +vt 0.6252 0.4135 +vt 0.6723 0.3631 +vt 0.6776 0.3623 +vt 0.6712 0.3785 +vt 0.6765 0.3780 +vt 0.6722 0.3505 +vt 0.6775 0.3494 +vt 0.6766 0.3388 +vt 0.6822 0.3488 +vt 0.6713 0.3400 +vt 0.6650 0.3523 +vt 0.6643 0.3419 +vt 0.6652 0.3644 +vt 0.6628 0.3259 +vt 0.6684 0.3243 +vt 0.6634 0.3332 +vt 0.6823 0.3617 +vt 0.6815 0.3770 +vt 0.6744 0.3183 +vt 0.6730 0.3233 +vt 0.6699 0.3312 +vt 0.6240 0.4069 +vt 0.6290 0.4182 +vt 0.6296 0.4067 +vt 0.6242 0.4276 +vt 0.6218 0.4601 +vt 0.6242 0.4453 +vt 0.6146 0.4661 +vt 0.6176 0.4615 +vt 0.7141 0.4094 +vt 0.7173 0.4000 +vt 0.6954 0.4920 +vt 0.6975 0.4733 +vt 0.6880 0.4796 +vt 0.6293 0.4400 +vt 0.6286 0.4293 +vt 0.6166 0.4400 +vt 0.6149 0.4502 +vt 0.6173 0.4495 +vt 0.6205 0.4480 +vt 0.3981 0.8175 +vt 0.3813 0.8286 +vt 0.3893 0.8504 +vt 0.3643 0.8387 +vt 0.4136 0.9023 +vt 0.4153 0.9429 +vt 0.3988 0.9095 +vt 0.3934 0.8712 +vt 0.3630 0.8415 +vt 0.3901 0.8353 +vt 0.3608 0.8647 +vt 0.3609 0.8516 +vt 0.4125 0.9787 +vt 0.3991 0.9787 +vt 0.4001 0.9380 +vt 0.3766 0.8689 +vt 0.3855 0.8798 +vt 0.3739 0.8600 +vt 0.3988 0.9140 +vt 0.4034 0.9357 +vt 0.4027 0.9078 +vt 0.3873 0.8563 +vt 0.6823 0.3208 +vt 0.6570 0.3222 +vt 0.5737 0.3149 +vt 0.5741 0.3915 +vt 0.5598 0.3803 +vt 0.5170 0.3236 +vt 0.5432 0.3530 +vt 0.5934 0.3267 +vt 0.5841 0.3906 +vt 0.5923 0.3712 +vt 0.5998 0.3370 +vt 0.6020 0.3167 +vt 0.4122 0.0879 +vt 0.4154 0.0556 +vt 0.4269 0.0837 +vt 0.4173 0.0203 +vt 0.4282 0.0391 +vt 0.4430 0.1591 +vt 0.4252 0.1234 +vt 0.4550 0.1371 +vt 0.4037 0.0205 +vt 0.3973 0.0234 +vt 0.4909 0.2674 +vt 0.4666 0.2091 +vt 0.4857 0.1688 +vn 0.9461 0.2521 -0.2031 +vn 0.9208 0.2272 -0.3169 +vn 0.9693 0.1281 -0.2098 +vn 0.9053 0.2115 -0.3683 +vn 0.9397 0.3219 -0.1152 +vn 0.8665 0.2713 -0.4189 +vn 0.9901 0.0628 -0.1251 +vn 0.8831 0.2428 -0.4013 +vn 0.9318 0.1382 -0.3357 +vn 0.9095 0.4116 -0.0575 +vn 0.7912 0.2639 -0.5517 +vn 0.6387 0.4890 -0.5940 +vn 0.7830 0.4291 -0.4502 +vn 0.6523 0.4847 -0.5827 +vn 0.9062 0.3947 -0.1516 +vn 0.6421 0.4812 -0.5968 +vn 0.9722 0.2253 -0.0634 +vn 0.9684 0.1733 -0.1790 +vn 0.9687 0.2466 0.0291 +vn 0.9114 0.3310 -0.2444 +vn 0.9244 0.3335 -0.1850 +vn 0.8168 0.4242 -0.3909 +vn 0.8741 0.3143 -0.3703 +vn 0.9780 0.1085 0.1780 +vn 0.9510 0.1431 0.2742 +vn 0.9977 0.0610 0.0291 +vn 0.6906 0.5537 -0.4652 +vn 0.2315 0.6281 -0.7428 +vn 0.2339 0.6816 -0.6933 +vn 0.4172 0.6038 -0.6792 +vn 0.1151 0.6577 -0.7444 +vn 0.0000 0.6537 -0.7567 +vn 0.4617 0.5793 -0.6717 +vn 0.4285 0.5814 -0.6916 +vn 0.0000 0.6981 -0.7160 +vn 0.5712 0.0384 0.8199 +vn 0.4838 0.0396 0.8743 +vn 0.4307 0.0884 0.8981 +vn 0.4777 0.0112 0.8784 +vn 0.4669 0.0288 0.8838 +vn 0.4774 0.0248 0.8783 +vn 0.1169 0.6925 -0.7118 +vn 0.0000 0.7242 -0.6895 +vn 0.0000 -0.3066 0.9518 +vn 0.0000 -0.4906 0.8713 +vn 0.1588 -0.1046 0.9817 +vn 0.3044 0.7055 -0.6400 +vn 0.1087 0.7420 -0.6615 +vn 0.8283 0.5476 -0.1187 +vn 0.6781 0.6996 -0.2252 +vn 0.4255 0.8084 -0.4068 +vn 0.0000 0.9607 -0.2776 +vn 0.0000 0.8598 -0.5106 +vn 0.1243 0.8540 -0.5051 +vn 0.8499 0.0085 0.5269 +vn 0.9200 -0.1510 0.3616 +vn 0.8126 -0.2723 0.5152 +vn 0.6057 -0.1196 0.7866 +vn 0.6632 -0.0151 0.7482 +vn 0.7784 0.0299 0.6270 +vn 0.8040 -0.4887 0.3387 +vn 0.7427 -0.3039 0.5967 +vn 0.9698 0.2049 0.1317 +vn 0.8487 -0.4206 0.3205 +vn 0.8563 -0.4949 0.1475 +vn 0.9155 -0.3395 0.2159 +vn 0.9112 0.2002 0.3601 +vn 0.4388 -0.2012 0.8758 +vn 0.4021 -0.0974 0.9104 +vn 0.4297 -0.0469 0.9018 +vn 0.5983 -0.0150 0.8011 +vn 0.7479 -0.0185 0.6635 +vn 0.5210 -0.3211 0.7908 +vn 0.4205 0.8898 -0.1773 +vn 0.2319 0.9528 -0.1956 +vn 0.1135 0.9669 -0.2282 +vn 0.2858 0.9128 -0.2918 +vn 0.1878 0.9482 -0.2560 +vn 0.0460 0.9613 -0.2716 +vn 0.0000 0.9734 -0.2288 +vn 0.1096 0.9359 -0.3347 +vn 0.0000 0.9489 -0.3157 +vn 0.9675 0.1856 0.1716 +vn 0.9817 0.0152 0.1898 +vn 0.9823 0.1570 0.1024 +vn 0.8950 0.0117 0.4458 +vn 0.9529 -0.0037 0.3031 +vn 0.9531 0.2824 -0.1087 +vn 0.8441 0.0301 0.5353 +vn 0.8323 -0.0162 0.5540 +vn 0.7787 0.3464 -0.5230 +vn 0.9705 -0.0643 0.2322 +vn 0.6789 -0.0150 0.7341 +vn 0.5181 -0.0168 0.8551 +vn 0.1803 -0.9775 -0.1092 +vn 0.7925 -0.5757 0.2011 +vn 0.3552 -0.9344 -0.0245 +vn -0.0108 -0.4275 -0.9039 +vn 0.4193 0.3136 -0.8520 +vn 0.7809 0.1180 -0.6134 +vn -0.5709 -0.6130 -0.5461 +vn -0.4322 -0.6225 -0.6524 +vn 0.9079 -0.3681 -0.2006 +vn -0.0091 -0.9008 -0.4340 +vn -0.1442 -0.7067 -0.6926 +vn 0.8402 -0.3101 -0.4448 +vn -0.6367 -0.7637 -0.1062 +vn -0.5434 -0.8358 0.0783 +vn 0.2897 0.8387 0.4611 +vn 0.5408 0.7346 0.4096 +vn 0.4772 0.7221 0.5008 +vn 0.5399 0.6954 0.4742 +vn 0.2701 0.8282 0.4910 +vn 0.1453 0.8028 0.5783 +vn 0.3280 0.8128 0.4814 +vn 0.9005 0.4082 -0.1500 +vn 0.8390 0.4802 -0.2559 +vn 0.6814 -0.0624 -0.7293 +vn -0.5883 0.5293 -0.6114 +vn -0.2113 0.7844 -0.5831 +vn -0.7541 -0.0288 -0.6561 +vn -0.7326 0.2914 -0.6151 +vn -0.7233 -0.1090 -0.6819 +vn -0.1888 0.6806 -0.7079 +vn -0.6156 -0.0400 -0.7870 +vn -0.6358 0.2348 -0.7352 +vn 0.0000 0.7310 -0.6823 +vn -0.5543 0.5818 -0.5951 +vn -0.6942 0.5031 -0.5147 +vn 0.2171 0.6056 -0.7656 +vn 0.9715 0.1908 -0.1407 +vn 0.7533 -0.1436 -0.6418 +vn 0.9351 0.2828 -0.2133 +vn 0.3562 0.8682 0.3453 +vn -0.0284 0.8238 0.5661 +vn 0.0406 0.8713 0.4891 +vn -0.0286 0.8260 0.5630 +vn 0.2163 0.9236 0.3164 +vn 0.6146 0.3960 0.6822 +vn 0.3393 0.4586 0.8213 +vn 0.3648 0.7150 0.5964 +vn -0.0352 0.7168 0.6964 +vn 0.2983 0.9298 0.2153 +vn 0.2070 0.9766 0.0584 +vn 0.1210 0.9661 0.2280 +vn 0.2275 0.9336 0.2769 +vn 0.3890 0.8594 0.3317 +vn 0.8856 -0.3421 0.3141 +vn 0.6204 0.3302 0.7114 +vn 0.6129 0.1742 0.7707 +vn -0.0167 0.5616 0.8272 +vn 0.0187 0.5722 0.8199 +vn 0.0544 0.7486 0.6607 +vn 0.1674 0.7658 0.6208 +vn 0.1782 0.7414 0.6469 +vn 0.2477 0.8641 0.4381 +vn 0.2818 0.7820 0.5559 +vn 0.2347 0.8377 0.4931 +vn 0.1373 0.7886 0.5993 +vn 0.0000 0.9570 0.2900 +vn 0.0000 0.8649 0.5020 +vn 0.0508 0.9140 0.4025 +vn 0.0973 0.7923 0.6023 +vn 0.1771 0.8686 0.4628 +vn 0.7946 0.5452 0.2670 +vn 0.8917 0.3740 0.2550 +vn 0.7683 0.6032 0.2142 +vn 0.5817 0.7783 0.2364 +vn 0.6287 0.7652 0.1383 +vn 0.8520 0.2315 0.4695 +vn 0.8839 0.3512 0.3088 +vn 0.7729 -0.2160 0.5966 +vn 0.6659 -0.3040 0.6813 +vn 0.7889 0.6009 0.1285 +vn 0.9406 0.1468 0.3061 +vn 0.7552 -0.4812 0.4450 +vn 0.8612 0.4929 0.1238 +vn 0.8374 0.5089 0.1993 +vn 0.8178 0.4509 0.3575 +vn 0.8329 0.4366 0.3401 +vn 0.8309 0.2418 0.5011 +vn 0.4611 0.1201 -0.8791 +vn 0.5331 -0.5695 0.6257 +vn 0.8762 0.4626 0.1355 +vn 0.6449 -0.3262 0.6911 +vn 0.3882 -0.8220 0.4168 +vn 0.3490 -0.7891 0.5054 +vn 0.3735 -0.7946 0.4786 +vn 0.4933 -0.6437 0.5850 +vn 0.2116 -0.5791 0.7873 +vn 0.0752 -0.8151 0.5743 +vn 0.6800 -0.2022 0.7048 +vn 0.2353 -0.8777 0.4173 +vn 0.0000 -0.9214 0.3886 +vn 0.0000 -0.5739 0.8189 +vn 0.0000 -0.7209 0.6930 +vn 0.0581 -0.8120 0.5807 +vn 0.6184 -0.4279 0.6591 +vn -0.5536 -0.7831 -0.2834 +vn -0.1348 -0.9391 0.3161 +vn -0.5072 -0.8527 -0.1253 +vn 0.0225 -0.9240 0.3816 +vn -0.6364 0.6131 -0.4681 +vn 0.4109 -0.6906 0.5951 +vn 0.4200 -0.5970 0.6835 +vn 0.6039 -0.7091 -0.3639 +vn 0.6791 0.7320 0.0554 +vn 0.3809 0.9091 -0.1682 +vn 0.0029 0.9368 -0.3499 +vn 0.3330 -0.7530 0.5676 +vn 0.4542 -0.8054 0.3807 +vn 0.2127 -0.9350 0.2839 +vn -0.4686 -0.8571 -0.2139 +vn -0.0228 -0.9940 0.1071 +vn 0.0000 -0.9821 -0.1882 +vn 0.7897 -0.6080 -0.0819 +vn 0.5952 -0.7782 -0.2001 +vn 0.7129 -0.7013 0.0015 +vn 0.7922 -0.6049 0.0802 +vn 0.5995 -0.7993 -0.0413 +vn 0.7790 -0.5758 0.2481 +vn 0.9472 -0.2160 0.2369 +vn 0.9241 -0.3797 0.0434 +vn 0.9574 -0.1484 0.2476 +vn 0.9487 0.0461 0.3128 +vn 0.9175 -0.0637 0.3925 +vn 0.9217 -0.3671 0.1254 +vn 0.7356 -0.5047 0.4518 +vn 0.6403 -0.4551 0.6188 +vn 0.8861 0.2194 0.4082 +vn 0.8911 0.1947 0.4099 +vn 0.9469 0.1744 0.2701 +vn 0.9075 0.2593 0.3305 +vn 0.9043 0.3841 0.1862 +vn 0.6530 -0.1609 0.7401 +vn 0.3943 -0.1053 0.9129 +vn 0.3126 -0.0507 0.9485 +vn 0.4436 -0.4072 0.7983 +vn 0.7069 -0.4240 0.5661 +vn 0.7190 -0.5740 0.3917 +vn 0.0000 -0.2638 0.9646 +vn 0.3146 -0.1462 0.9379 +vn 0.4201 -0.0782 0.9041 +vn 0.2282 -0.1237 0.9657 +vn 0.1650 -0.2144 0.9627 +vn 0.0000 -0.1228 0.9924 +vn 0.7414 -0.6316 0.2264 +vn 0.6796 -0.6033 0.4174 +vn 0.4272 -0.6470 0.6315 +vn 0.0000 -0.6473 0.7622 +vn 0.7946 -0.4053 0.4520 +vn 0.3297 0.8623 0.3844 +vn 0.4427 0.8598 0.2544 +vn 0.3706 0.8045 0.4640 +vn 0.5425 0.8259 0.1535 +vn 0.5524 0.7610 0.3402 +vn 0.1573 0.8092 0.5661 +vn 0.3077 0.7807 0.5438 +vn 0.6013 0.3955 0.6942 +vn 0.6878 0.6725 0.2730 +vn 0.0391 0.7548 0.6548 +vn 0.6529 0.6402 0.4046 +vn 0.0000 0.9979 0.0649 +vn -0.0077 0.9398 -0.3416 +vn -0.0241 0.9474 -0.3190 +vn 0.0000 0.9361 -0.3517 +vn 0.0000 0.7763 0.6303 +vn 0.0000 0.8842 0.4671 +vn 0.0000 0.8467 0.5321 +vn 0.5218 0.8276 0.2066 +vn 0.6667 0.6732 0.3198 +vn 0.5091 0.7868 0.3489 +vn 0.6097 0.7107 0.3508 +vn 0.1948 0.8221 0.5349 +vn 0.7592 0.6035 0.2436 +vn 0.8385 0.4824 0.2531 +vn 0.9191 0.0142 0.3937 +vn 0.9278 0.2681 0.2593 +vn 0.8376 0.2998 0.4567 +vn 0.3233 0.9463 -0.0063 +vn 0.4816 0.8026 0.3518 +vn 0.8683 0.4856 0.1014 +vn 0.8630 0.4828 0.1490 +vn 0.8523 0.5096 0.1178 +vn 0.8714 0.4632 0.1614 +vn 0.8804 0.4310 0.1978 +vn 0.8415 0.5325 0.0914 +vn 0.9048 0.3949 0.1595 +vn 0.9313 0.3608 0.0501 +vn 0.8118 0.5827 0.0374 +vn 0.8023 0.5935 0.0634 +vn 0.8542 0.5184 0.0399 +vn 0.8781 0.4773 -0.0329 +vn 0.7025 -0.0488 0.7100 +vn 0.7552 -0.2058 0.6224 +vn 0.8851 0.2334 0.4025 +vn 0.8373 0.2477 0.4874 +vn 0.8366 0.3992 0.3751 +vn 0.8820 0.1229 0.4550 +vn 0.9523 0.2275 0.2032 +vn 0.9440 0.1485 0.2946 +vn 0.8339 0.0809 0.5459 +vn 0.6595 -0.0613 0.7492 +vn 0.9287 0.3149 0.1955 +vn 0.9014 0.3750 0.2165 +vn 0.8593 0.4531 0.2371 +vn 0.8576 0.4722 0.2040 +vn 0.8797 0.4214 0.2202 +vn 0.7314 0.6796 -0.0558 +vn 0.4828 0.8397 -0.2484 +vn 0.3905 0.9041 -0.1735 +vn 0.6490 0.7537 -0.1033 +vn 0.5767 0.8093 -0.1115 +vn 0.3354 0.9149 -0.2244 +vn 0.4980 0.8491 -0.1761 +vn 0.7681 0.6397 -0.0274 +vn 0.7059 0.7076 -0.0322 +vn 0.6357 0.7635 -0.1140 +vn 0.4348 -0.1517 0.8877 +vn 0.6015 -0.0503 0.7973 +vn 0.2839 -0.2446 0.9271 +vn 0.1164 -0.4732 0.8732 +vn 0.1501 -0.6904 0.7077 +vn 0.3713 -0.6227 0.6887 +vn 0.0000 -0.4913 0.8710 +vn 0.0000 -0.7056 0.7085 +vn 0.2866 -0.4133 0.8643 +vn 0.4494 -0.2263 0.8642 +vn 0.4694 -0.3007 0.8302 +vn 0.2694 -0.3353 0.9027 +vn 0.0000 -0.3359 0.9419 +vn 0.1339 -0.3113 0.9408 +vn 0.0000 -0.2423 0.9702 +vn 0.1152 -0.3949 0.9114 +vn 0.0000 -0.4135 0.9105 +vn 0.9692 0.2457 -0.0166 +vn 0.7649 0.0229 0.6437 +vn 0.9046 0.0535 0.4228 +vn 0.9886 0.1495 0.0183 +vn 0.9882 0.0514 0.1445 +vn 0.5530 -0.5145 0.6553 +vn 0.8134 -0.1635 0.5582 +vn 0.5154 -0.7365 0.4380 +vn 0.6084 -0.7477 0.2658 +vn 0.7797 -0.5966 0.1902 +vn 0.5925 -0.8006 -0.0893 +vn 0.4053 -0.8439 0.3515 +vn 0.8314 -0.5344 0.1523 +vn 0.6450 -0.7393 -0.1933 +vn 0.7473 -0.6224 -0.2326 +vn 0.6753 -0.6820 -0.2809 +vn 0.9199 -0.3919 0.0147 +vn 0.5200 -0.8313 -0.1961 +vn 0.5201 -0.8233 -0.2271 +vn 0.0638 -0.8465 0.5286 +vn 0.3178 -0.8795 0.3541 +vn 0.4913 -0.8704 0.0309 +vn 0.8014 -0.5906 -0.0940 +vn 0.8081 -0.5888 -0.0180 +vn 0.6004 -0.7907 -0.1198 +vn 0.6403 -0.7583 -0.1223 +vn 0.7619 -0.6435 -0.0731 +vn 0.6069 -0.7272 -0.3207 +vn 0.6690 -0.7392 0.0782 +vn -0.0114 -0.7285 0.6849 +vn 0.8677 0.4937 -0.0576 +vn 0.5107 0.7719 0.3785 +vn 0.6139 0.7535 0.2351 +vn 0.7139 0.5820 0.3892 +vn 0.4424 0.6411 0.6271 +vn 0.4889 0.5419 0.6835 +vn 0.4367 0.5770 0.6902 +vn 0.6927 0.4663 0.5501 +vn 0.1266 0.3410 0.9315 +vn 0.3627 -0.2486 0.8981 +vn 0.3774 0.0584 0.9242 +vn 0.5531 0.2388 0.7982 +vn 0.2640 0.5331 0.8038 +vn 0.4023 0.2092 0.8913 +vn 0.3837 0.6668 0.6388 +vn 0.9627 0.2689 0.0296 +vn 0.8432 0.1794 0.5067 +vn 0.9914 -0.0684 0.1112 +vn 0.2319 0.5500 0.8023 +vn 0.0000 0.3941 0.9190 +vn 0.0000 0.1573 0.9875 +vn 0.0000 0.5578 0.8300 +vn -0.0554 -0.6311 0.7737 +vn 0.0000 -0.3246 0.9458 +vn 0.3031 -0.3053 0.9027 +vn 0.9362 -0.3495 0.0349 +vn 0.9365 -0.3211 0.1408 +vn 0.2616 -0.4242 0.8669 +vn 0.4073 -0.4945 0.7678 +vn 0.5006 -0.3766 0.7794 +vn 0.3089 -0.3165 0.8968 +vn 0.7606 0.5641 -0.3212 +vn 0.4475 0.7766 -0.4433 +vn 0.4452 0.4876 0.7510 +vn 0.1506 -0.0185 0.9884 +vn 0.1653 0.8188 0.5497 +vn 0.1322 0.9488 -0.2868 +vn 0.6126 -0.5175 0.5974 +vn 0.7013 -0.4134 0.5807 +vn 0.8232 -0.4819 0.3000 +vn 0.8847 -0.4660 0.0127 +vn 0.9622 -0.2691 0.0419 +vn 0.9122 -0.3857 0.1382 +vn 0.8887 -0.3870 0.2459 +vn 0.8208 -0.4093 0.3984 +vn 0.5987 0.5393 -0.5922 +vn 0.7361 0.4303 -0.5224 +vn 0.4485 0.6475 -0.6161 +vn 0.5971 0.5128 -0.6168 +vn 0.4266 0.6195 -0.6589 +vn 0.3205 0.6668 -0.6727 +vn 0.7449 0.4434 -0.4985 +vn 0.8474 0.3321 -0.4141 +vn 0.4826 0.5794 -0.6568 +vn 0.8340 0.2959 -0.4656 +vn -0.0052 0.9246 -0.3807 +vn 0.0873 0.6950 -0.7136 +vn 0.0287 0.8215 -0.5694 +vn 0.4447 0.5940 -0.6703 +vn 0.1107 0.6983 -0.7071 +vn 0.2991 0.7342 -0.6094 +vn 0.2424 0.7700 -0.5901 +vn 0.9369 -0.2676 0.2250 +vn 0.9554 -0.1037 0.2764 +vn 0.9498 -0.3017 0.0823 +vn 0.9813 -0.1799 0.0684 +vn 0.9846 -0.1733 -0.0213 +vn 0.9972 -0.0120 -0.0731 +vn 0.8396 -0.5422 0.0318 +vn 0.6209 -0.4565 -0.6373 +vn 0.4686 -0.8571 -0.2139 +vn 0.7142 -0.3922 -0.5797 +vn 0.5072 -0.8527 -0.1253 +vn 0.0000 -0.7552 -0.6555 +vn 0.8986 0.4386 0.0050 +vn 0.9302 0.3481 -0.1165 +vn 0.9074 0.4047 -0.1133 +vn 0.2358 -0.9711 -0.0360 +vn 0.0000 -1.0000 0.0046 +vn 0.0000 -0.9988 -0.0478 +vn 0.4302 0.8473 -0.3115 +vn 0.3587 0.8872 -0.2900 +vn 0.0000 0.9496 -0.3134 +vn 0.8663 0.4978 -0.0414 +vn 0.6156 -0.0400 -0.7870 +vn 0.6274 -0.2548 -0.7358 +vn 0.7233 -0.1090 -0.6819 +vn 0.7294 -0.2795 -0.6243 +vn 0.0000 0.2999 -0.9539 +vn 0.0000 -0.2633 -0.9647 +vn 0.8088 0.5431 -0.2253 +vn 0.9212 0.3332 -0.2008 +vn 0.7888 0.5757 -0.2155 +vn 0.9356 -0.3091 -0.1704 +vn 0.8311 -0.5432 -0.1189 +vn 0.9842 -0.0016 -0.1771 +vn 0.9915 -0.0196 -0.1286 +vn 0.9046 0.3909 -0.1695 +vn 0.3110 0.6448 0.6982 +vn 0.6946 -0.7098 -0.1169 +vn 0.6170 -0.7814 -0.0933 +vn 0.8735 -0.4736 -0.1122 +vn 0.9950 0.0389 -0.0922 +vn 0.0000 0.9373 -0.3484 +vn 0.0000 0.9266 -0.3760 +vn 0.4000 0.8422 -0.3614 +vn 0.3005 0.8741 -0.3815 +vn 0.6355 0.7363 -0.2323 +vn 0.6877 0.6899 -0.2261 +vn 0.6801 0.6856 -0.2596 +vn -0.8604 0.4956 0.1180 +vn -0.8486 0.4408 0.2923 +vn -0.8762 0.4626 0.1355 +vn -0.8329 0.4366 0.3401 +vn -0.8374 0.5089 0.1993 +vn -0.8247 0.4162 0.3828 +vn -0.4611 0.1201 -0.8791 +vn -0.8178 0.4509 0.3575 +vn -0.3599 0.4473 -0.8187 +vn -0.2171 0.6056 -0.7656 +vn -0.6791 0.7320 0.0554 +vn -0.8735 -0.4736 -0.1122 +vn -0.9815 -0.1795 -0.0660 +vn -0.7280 -0.6781 -0.1007 +vn -0.9950 0.0389 -0.0922 +vn -0.9321 0.3499 -0.0930 +vn -0.0029 0.9368 -0.3499 +vn -0.3809 0.9091 -0.1682 +vn -0.7418 0.6701 0.0280 +vn -0.5434 -0.1339 -0.8287 +vn -0.6039 -0.7091 -0.3639 +vn 0.5536 -0.7831 -0.2834 +vn 0.6358 0.2348 -0.7352 +vn 0.7541 -0.0288 -0.6561 +vn -0.8309 0.2418 0.5011 +vn 0.6472 -0.7452 0.1606 +vn 0.7978 -0.5037 -0.3312 +vn 0.6491 -0.7569 -0.0761 +vn 0.8178 -0.4696 0.3327 +vn 0.6513 -0.5982 0.4668 +vn 0.7184 -0.6696 -0.1881 +vn 0.3436 -0.9263 -0.1543 +vn 0.6623 -0.1268 0.7384 +vn 0.0000 -0.3693 0.9293 +vn 0.0000 -0.4704 0.8824 +vn 0.9473 -0.1775 0.2666 +vn 0.3310 -0.8962 0.2953 +vn 0.7890 -0.3247 0.5216 +vn 0.4592 -0.8796 0.1241 +vn 0.6627 -0.6709 0.3325 +vn 0.7925 -0.5763 0.1993 +vn 0.8707 -0.3982 0.2886 +vn 0.3941 -0.8863 0.2429 +vn 0.7239 -0.4853 0.4904 +vn 0.6654 -0.1179 0.7371 +vn 0.9206 -0.3901 -0.0167 +vn 0.8206 0.1611 0.5484 +vn 0.6245 0.0725 0.7777 +vn 0.8528 -0.0475 0.5199 +vn 0.9784 -0.1214 -0.1670 +vn 0.4044 -0.4647 0.7877 +vn 0.8897 0.1521 0.4303 +vn 0.4046 -0.2463 0.8807 +vn 0.2344 -0.0113 0.9721 +vn 0.7382 0.3495 0.5769 +vn 0.8988 0.1980 0.3911 +vn 0.9807 -0.0365 0.1919 +vn 0.6809 0.7318 0.0284 +vn 0.9998 0.0169 -0.0088 +vn 0.8480 0.4299 0.3098 +vn 0.9819 -0.0545 0.1814 +vn 0.9698 0.0264 0.2425 +vn 0.9330 0.0583 0.3550 +vn 0.8615 0.4649 0.2041 +vn 0.7936 0.5992 0.1055 +vn 0.9436 0.3208 0.0814 +vn 0.6894 0.7235 -0.0338 +vn 0.7945 0.3432 0.5010 +vn 0.8177 0.5610 0.1290 +vn 0.5214 0.3315 0.7862 +vn 0.2860 0.3995 0.8710 +vn 0.6135 0.4266 0.6645 +vn 0.7797 0.0205 0.6258 +vn 0.8621 -0.2613 0.4340 +vn 0.8423 -0.3548 0.4057 +vn 0.9051 0.3038 0.2973 +vn 0.6486 0.6336 0.4216 +vn 0.3702 0.8440 0.3880 +vn 0.9518 -0.2485 0.1799 +vn 0.9730 0.1491 0.1763 +vn 0.8753 -0.4614 0.1448 +vn 0.0959 0.9361 -0.3383 +vn 0.1048 0.9535 -0.2825 +vn 0.1034 0.9865 -0.1266 +vn 0.1563 0.9459 -0.2843 +vn 0.0000 0.9890 -0.1478 +vn 0.0000 0.9445 -0.3283 +vn 0.1275 0.8791 -0.4592 +vn 0.1064 0.9344 -0.3398 +vn 0.1492 0.9253 -0.3485 +vn 0.4278 0.8934 -0.1371 +vn 0.6411 0.7674 -0.0125 +vn 0.5485 0.8319 -0.0840 +vn 0.3214 0.9118 -0.2554 +vn 0.7306 0.6736 0.1115 +vn 0.7799 0.6251 0.0307 +vn 0.7956 0.4235 0.4331 +vn 0.7306 0.6776 -0.0836 +vn 0.8864 0.2323 0.4003 +vn 0.8365 -0.2363 0.4944 +vn 0.9306 0.2062 0.3024 +vn 0.9903 0.0976 0.0989 +vn 0.9755 -0.0135 0.2194 +vn 0.9247 -0.0046 0.3806 +vn 0.6145 0.7541 0.2315 +vn 0.5256 0.6211 0.5813 +vn 0.9556 0.2855 0.0728 +vn 0.7741 0.0154 0.6329 +vn 0.7346 0.1909 0.6511 +vn -0.3781 0.8723 0.3098 +vn 0.8034 -0.4675 0.3686 +vn 0.5594 -0.3754 0.7389 +vn 0.8307 0.1838 0.5255 +vn 0.3183 0.9411 -0.1140 +vn 0.7491 0.6624 0.0002 +vn 0.6883 0.7253 -0.0098 +vn 0.6072 0.6367 -0.4752 +vn 0.8307 0.4781 -0.2849 +vn 0.8983 0.4226 -0.1201 +vn -0.7455 0.6504 0.1451 +vn 0.6795 0.5814 0.4474 +vn 0.5966 0.4121 0.6886 +vn -0.2885 0.3980 0.8708 +vn -0.1817 -0.3441 0.9211 +vn 0.3132 0.3367 0.8879 +vn 0.6675 0.7420 0.0620 +vn 0.8986 0.4383 0.0193 +vn 0.7598 0.6100 0.2247 +vn 0.9625 0.2677 -0.0443 +vn 0.9459 0.2254 -0.2332 +vn 0.5995 0.7955 0.0878 +vn 0.2535 0.7562 0.6033 +vn 0.9719 0.1790 -0.1529 +vn 0.9176 0.2927 -0.2688 +vn 0.2416 0.9129 0.3289 +vn 0.9405 0.2532 -0.2264 +vn 0.9783 0.2042 -0.0339 +vn 0.9666 0.2521 -0.0460 +vn 0.9817 0.1865 0.0376 +vn 0.9066 0.4118 0.0924 +vn 0.3380 0.4837 0.8073 +vn 0.8184 0.5578 0.1378 +vn 0.9648 0.2568 0.0572 +vn 0.1343 0.7598 -0.6361 +vn 0.0824 0.8422 -0.5327 +vn 0.6554 0.7533 -0.0540 +vn 0.7269 0.6845 0.0562 +vn 0.1271 0.8181 -0.5608 +vn 0.3461 0.9357 -0.0680 +vn 0.0607 0.9937 -0.0947 +vn 0.0000 0.9016 -0.4326 +vn 0.0000 0.8143 -0.5805 +vn 0.6471 0.7623 0.0080 +vn 0.7308 0.6550 -0.1923 +vn 0.6285 0.7776 -0.0189 +vn 0.5478 0.8355 -0.0428 +vn 0.7163 0.6300 -0.2999 +vn -0.1303 0.2501 -0.9594 +vn -0.1672 0.5252 -0.8343 +vn -0.6596 -0.6565 -0.3658 +vn 0.6128 0.7461 -0.2604 +vn 0.1741 0.3336 -0.9265 +vn 0.5544 0.8321 -0.0111 +vn -0.5963 -0.7069 -0.3803 +vn -0.4856 -0.7575 -0.4363 +vn -0.4686 -0.7518 -0.4638 +vn -0.2695 -0.7941 -0.5447 +vn -0.4454 -0.7530 -0.4844 +vn -0.5138 -0.7761 -0.3655 +vn -0.3168 -0.8032 -0.5044 +vn -0.6904 -0.6778 -0.2525 +vn 0.5840 0.7763 0.2371 +vn 0.6370 0.6007 0.4830 +vn 0.5821 0.6321 0.5115 +vn 0.7255 0.6795 0.1091 +vn 0.6413 0.7254 0.2499 +vn 0.6774 0.6272 0.3841 +vn 0.7980 0.4978 0.3396 +vn 0.5673 0.7513 0.3371 +vn 0.6557 0.6499 0.3843 +vn 0.6166 0.7799 0.1071 +vn 0.7881 0.6151 0.0222 +vn 0.6605 0.7497 -0.0411 +vn 0.7075 0.6984 0.1081 +vn 0.0214 -0.8707 -0.4914 +vn 0.4306 -0.1322 -0.8928 +vn 0.2848 0.1867 -0.9402 +vn -0.3582 -0.8316 -0.4243 +vn -0.5377 -0.7964 -0.2767 +vn -0.6097 -0.7869 -0.0950 +vn -0.5876 -0.8091 -0.0029 +vn -0.4120 -0.9109 -0.0211 +vn 0.5215 -0.6521 -0.5502 +vn -0.1408 -0.9482 -0.2846 +vn 0.2160 -0.9619 -0.1676 +vn -0.4898 -0.8480 -0.2023 +vn -0.3603 -0.8984 -0.2512 +vn -0.2437 -0.9246 -0.2926 +vn -0.3967 -0.9055 -0.1502 +vn -0.0200 -0.9346 -0.3552 +vn -0.1722 -0.8703 -0.4613 +vn 0.7384 -0.5815 -0.3415 +vn 0.0475 -0.9987 -0.0155 +vn 0.0027 -0.9989 -0.0462 +vn -0.3984 -0.9109 -0.1075 +vn 0.5952 -0.8033 0.0196 +vn 0.8838 -0.4357 -0.1702 +vn 0.4740 -0.5862 -0.6570 +vn 0.5264 -0.4328 -0.7318 +vn 0.6726 0.5151 0.5313 +vn -0.5638 -0.7641 -0.3136 +vn -0.5757 -0.8162 0.0473 +vn -0.6585 -0.7402 -0.1358 +vn -0.3789 -0.9078 -0.1795 +vn -0.4618 -0.8723 -0.1606 +vn -0.4960 -0.8090 -0.3152 +vn -0.3843 -0.9218 0.0516 +vn -0.4748 -0.7779 -0.4116 +vn -0.4768 -0.8271 -0.2975 +vn -0.5966 -0.7469 -0.2934 +vn -0.3430 -0.9386 -0.0368 +vn -0.0427 -0.9160 0.3990 +vn -0.3601 -0.7574 0.5446 +vn -0.2022 -0.8778 0.4342 +vn 0.1032 -0.3584 0.9278 +vn 0.2485 -0.4421 0.8618 +vn -0.4655 -0.8805 -0.0896 +vn -0.4767 -0.8722 0.1095 +vn -0.5509 -0.8344 -0.0180 +vn -0.6635 -0.7405 -0.1067 +vn -0.7074 -0.6845 -0.1761 +vn -0.7363 -0.6508 -0.1851 +vn -0.6969 -0.6774 -0.2353 +vn -0.7489 -0.6311 -0.2022 +vn -0.6920 -0.6618 -0.2883 +vn -0.5882 -0.8083 0.0258 +vn -0.6013 -0.7824 -0.1620 +vn -0.4585 -0.8863 0.0646 +vn 0.4705 0.1532 0.8690 +vn 0.5380 0.3140 0.7823 +vn 0.5694 0.4761 0.6702 +vn 0.6115 0.3881 0.6895 +vn 0.5936 0.4450 0.6705 +vn 0.6221 0.3303 0.7099 +vn 0.5773 0.0689 0.8136 +vn 0.7360 0.2819 0.6154 +vn 0.6807 0.0086 0.7325 +vn 0.7511 0.4060 0.5205 +vn -0.1415 -0.9310 0.3364 +vn 0.3902 -0.5499 0.7385 +vn 0.2979 -0.5561 0.7759 +vn 0.5066 -0.8526 0.1282 +vn 0.6580 0.6858 -0.3107 +vn 0.3437 0.8892 -0.3020 +vn 0.6344 0.6929 -0.3426 +vn 0.7755 0.5705 -0.2701 +vn 0.0545 0.9359 -0.3481 +vn 0.3639 -0.9313 0.0138 +vn 0.3396 -0.9386 0.0607 +vn 0.5560 -0.8230 0.1165 +vn 0.5839 -0.8113 0.0267 +vn 0.0000 -0.9996 0.0279 +vn 0.0000 -0.9997 0.0240 +vn 0.0000 0.9405 -0.3399 +vn 0.6745 -0.7374 -0.0352 +vn 0.6385 -0.7633 0.0979 +vn 0.8226 0.4944 -0.2808 +vn 0.8244 0.5077 -0.2501 +vn 0.7688 0.5621 -0.3050 +vn 0.8999 0.3805 -0.2129 +vn 0.9060 0.3591 -0.2240 +vn 0.9092 0.3399 -0.2403 +vn 0.5315 -0.8440 0.0722 +vn 0.5535 -0.8323 -0.0281 +vn -0.6699 -0.7424 0.0105 +vn -0.5271 -0.8279 0.1915 +vn -0.6927 -0.7120 0.1147 +vn -0.5847 -0.6842 0.4359 +vn -0.3905 -0.9192 0.0502 +vn -0.6898 -0.7238 -0.0145 +vn -0.7158 -0.6956 0.0613 +vn 0.1375 -0.9904 0.0145 +vn 0.0779 -0.9961 0.0418 +vn 0.5758 -0.8148 -0.0674 +vn 0.3417 -0.9398 -0.0039 +vn -0.2225 -0.9741 0.0410 +vn 0.5136 -0.8549 0.0730 +vn 0.5256 -0.8354 0.1604 +vn 0.3015 -0.9523 0.0457 +vn 0.2820 -0.9593 0.0147 +vn 0.0000 -0.9998 0.0160 +vn 0.5210 -0.8536 0.0014 +vn 0.6978 -0.7154 -0.0353 +vn 0.2954 -0.9554 0.0021 +vn 0.4793 -0.8759 -0.0547 +vn 0.4872 -0.8705 -0.0692 +vn 0.2962 -0.9533 -0.0587 +vn 0.3106 -0.9481 -0.0681 +vn 0.6541 -0.7507 0.0925 +vn 0.9034 -0.4161 -0.1036 +vn 0.9860 -0.0183 -0.1658 +vn 0.9855 -0.0144 -0.1691 +vn 0.9690 0.0865 -0.2314 +vn 0.9076 -0.3858 -0.1656 +vn 0.9638 0.2101 -0.1640 +vn 0.4948 -0.8608 -0.1186 +vn 0.2585 -0.9566 -0.1342 +vn 0.7168 -0.6941 -0.0655 +vn 0.0000 -0.9975 -0.0702 +vn 0.0000 -0.9888 -0.1490 +vn -0.1446 0.9568 -0.2523 +vn -0.4494 0.8382 -0.3089 +vn -0.5697 0.7401 -0.3573 +vn -0.3111 0.8824 -0.3530 +vn 0.1155 0.9711 -0.2088 +vn 0.3221 0.9256 -0.1989 +vn 0.2433 0.9148 -0.3224 +vn -0.0748 0.9274 -0.3664 +vn 0.0000 0.9149 -0.4037 +vn -0.3090 0.8467 -0.4331 +vn 0.7866 0.6002 -0.1449 +vn 0.6447 0.7620 -0.0596 +vn 0.8556 0.4886 -0.1709 +vn 0.8459 0.5334 -0.0067 +vn 0.8891 0.4575 0.0140 +vn 0.8604 0.4956 0.1180 +vn 0.9231 0.3500 -0.1591 +vn 0.9321 0.3499 -0.0930 +vn 0.7418 0.6700 0.0280 +vn 0.4348 -0.9004 0.0145 +vn 0.2035 -0.9742 -0.0977 +vn 0.7745 -0.6234 0.1070 +vn 0.0466 -0.9677 -0.2477 +vn 0.2936 -0.9084 -0.2976 +vn 0.5067 -0.8411 -0.1892 +vn 0.7280 -0.6781 -0.1007 +vn 0.0000 -0.9158 -0.4016 +vn 0.1606 -0.9153 -0.3693 +vn 0.1805 -0.9444 -0.2748 +vn 0.3381 -0.9071 -0.2507 +vn 0.0000 -0.9586 -0.2847 +vn -0.4933 0.7294 -0.4740 +vn 0.0000 0.8648 -0.5021 +vn 0.0000 -0.9331 -0.3594 +vn -0.7142 -0.3922 -0.5797 +vn -0.7294 -0.2795 -0.6243 +vn 0.3599 0.4473 -0.8187 +vn 0.5434 -0.1339 -0.8287 +vn 0.8247 0.4162 0.3828 +vn -0.6274 -0.2548 -0.7358 +vn -0.6209 -0.4565 -0.6373 +vn 0.8486 0.4408 0.2923 +vn 0.9044 0.4238 0.0484 +vn 0.9931 0.0297 0.1136 +vn 0.9815 -0.1795 -0.0660 +vn 0.8236 0.2400 0.5139 +vn 0.4041 -0.5988 0.6914 +vn 0.7456 -0.0547 0.6641 +vn -0.1752 -0.9173 0.3576 +vn -0.1272 -0.9468 0.2954 +vn 0.4892 -0.6321 0.6009 +vn 0.7925 -0.1060 0.6005 +vn 0.8999 0.1347 0.4148 +vn 0.8828 -0.1119 0.4562 +vn 0.9055 0.3787 0.1915 +vn 0.8750 0.3163 0.3664 +vn 0.6617 -0.5839 0.4703 +vn -0.6876 -0.7255 -0.0311 +vn 0.6752 0.6728 -0.3021 +vn -0.0610 -0.0703 -0.9956 +vn 0.7098 0.7042 -0.0143 +vn 0.8335 0.5469 -0.0786 +vn -0.7171 -0.6260 -0.3062 +vn -0.5616 -0.6806 -0.4705 +vn -0.5178 -0.6417 -0.5657 +vn 0.8642 0.4711 0.1765 +vn 0.8611 0.5077 0.0250 +vn 0.9473 0.2579 0.1898 +vn 0.9229 0.3836 0.0308 +vn -0.3138 -0.9344 0.1687 +vn 0.6044 0.7966 0.0119 +vn 0.5865 -0.7831 -0.2065 +vn -0.6647 -0.5935 -0.4538 +vn -0.7742 -0.6228 -0.1126 +vn -0.7627 -0.5859 -0.2736 +vn -0.7851 -0.5962 -0.1679 +vn -0.7182 -0.6439 -0.2638 +vn 0.8220 0.3556 0.4448 +vn 0.9071 0.4060 0.1109 +vn 0.7567 0.6344 0.1578 +vn 0.9335 0.1669 0.3172 +vn 0.8940 0.0804 0.4407 +vn 0.9204 0.0081 0.3908 +vn 0.9842 0.0645 0.1647 +vn 0.9642 0.1428 0.2234 +vn 0.9774 0.1594 0.1386 +vn 0.9163 0.1617 0.3663 +vn 0.7658 0.1108 0.6334 +vn 0.5298 0.4357 0.7277 +vn 0.7219 0.4261 0.5452 +vn 0.6719 0.1825 0.7178 +vn 0.5282 0.2889 0.7985 +vn 0.8462 0.2304 0.4805 +vn 0.8489 0.3315 0.4116 +vn 0.4435 0.5161 0.7327 +vn 0.9499 0.2258 0.2161 +vn 0.4541 -0.8865 -0.0888 +vn 0.3082 -0.9439 -0.1183 +vn 0.0000 -0.9697 -0.2444 +vn 0.7539 -0.6522 -0.0791 +vn 0.6787 -0.6941 -0.2398 +vn 0.0000 -0.9902 0.1396 +vn 0.5549 -0.7879 -0.2670 +vn 0.6335 -0.7432 -0.2151 +vn 0.4920 -0.8657 -0.0925 +vn 0.6988 -0.6707 0.2484 +vn 0.7378 -0.6627 0.1281 +vn 0.0000 -0.9974 -0.0713 +vn 0.4539 -0.7841 0.4231 +vn 0.9954 0.0240 0.0928 +vn 0.6592 -0.7458 0.0957 +vn 0.6256 -0.7677 -0.1388 +vn 0.9902 0.1357 -0.0312 +vn 0.9585 0.2850 -0.0041 +vn 0.9969 0.0713 -0.0333 +vn 0.9660 0.2205 0.1349 +vn 0.8997 0.3933 0.1896 +vn 0.9508 0.3093 -0.0180 +vn 0.8223 0.4848 0.2981 +vn 0.9883 0.0350 0.1487 +vn 0.9865 -0.1241 0.1069 +vn 0.9550 -0.0469 0.2929 +vn 0.9368 -0.2559 0.2386 +vn 0.8677 0.4605 0.1872 +vn 0.3896 -0.9016 0.1877 +vn 0.2249 -0.9441 0.2411 +vn 0.1542 -0.9038 0.3991 +vn 0.2571 -0.9026 0.3453 +vn 0.5230 -0.8436 0.1215 +vn 0.5533 -0.7629 0.3342 +vn 0.7074 -0.4736 0.5245 +vn 0.5842 -0.7029 0.4058 +vn 0.1945 0.7453 0.6377 +vn 0.3627 0.6289 0.6877 +vn 0.0000 -0.9395 0.3424 +vn 0.7013 -0.6624 0.2633 +vn 0.7124 -0.5826 0.3912 +vn 0.9147 0.3174 -0.2500 +vn 0.8645 0.4382 -0.2462 +vn 0.7902 0.6029 -0.1098 +vn 0.6952 0.6997 -0.1643 +vn 0.8582 0.4952 -0.1352 +vn 0.9031 0.4260 0.0543 +vn 0.6754 0.6828 -0.2786 +vn 0.7794 0.5968 -0.1906 +vn 0.7828 0.5446 -0.3011 +vn 0.8877 0.4345 0.1524 +vn 0.9178 0.3969 0.0090 +vn 0.9487 0.2876 -0.1314 +vn 0.9315 0.2916 -0.2175 +vn 0.7105 0.2149 0.6701 +vn 0.7341 0.4555 0.5036 +vn 0.8072 0.4986 0.3157 +vn 0.8917 0.4422 -0.0963 +vn 0.9554 0.2131 -0.2045 +vn 0.2795 0.9021 -0.3286 +vn 0.2661 0.9086 -0.3218 +vn 0.4152 0.8497 -0.3249 +vn 0.5719 0.7507 -0.3305 +vn 0.1183 0.9398 -0.3205 +vn 0.4360 0.8599 -0.2655 +vn 0.5329 0.7984 -0.2803 +vn 0.2860 0.9123 -0.2932 +vn 0.1127 0.9359 -0.3336 +vn 0.5790 0.7873 -0.2117 +vn 0.0000 0.9486 -0.3165 +vn 0.5307 -0.8475 0.0109 +vn 0.2910 -0.9505 0.1088 +vn 0.0000 -0.9994 0.0344 +vn 0.0000 -0.9875 0.1573 +vn 0.2215 -0.9014 0.3721 +vn 0.0000 -0.9162 0.4006 +vn 0.4747 -0.8284 0.2974 +vn 0.6526 -0.7250 0.2200 +vn 0.6728 -0.7365 -0.0689 +vn 0.6637 -0.7033 0.2546 +vn 0.0000 -0.9199 0.3919 +vn 0.5907 -0.8061 -0.0337 +vn 0.4101 -0.8999 0.1479 +vn 0.4336 -0.6107 0.6626 +vn 0.6752 -0.6618 0.3258 +vn -0.2296 -0.7259 0.6483 +vn -0.0591 -0.9216 0.3836 +vn -0.0370 -0.9963 0.0773 +vn 0.8471 0.0249 0.5308 +vn 0.8120 0.5513 0.1917 +vn 0.9438 0.0431 -0.3278 +vn 0.9480 -0.0602 -0.3124 +vn 0.9661 0.1283 -0.2240 +vn 0.9232 0.1616 -0.3487 +vn 0.8851 0.0603 -0.4615 +vn 0.9046 -0.1353 -0.4042 +vn 0.9751 0.0401 -0.2180 +vn 0.9572 0.1976 -0.2113 +vn 0.9457 0.2416 -0.2173 +vn 0.7600 0.4220 -0.4942 +vn 0.8822 0.2748 -0.3824 +vn 0.4682 0.7750 -0.4243 +vn 0.8550 0.4596 -0.2401 +vn 0.6556 0.6745 -0.3393 +vn 0.7493 0.5698 -0.3374 +vn 0.6944 0.6186 -0.3676 +vn 0.4421 0.8381 -0.3195 +vn 0.8697 0.4143 -0.2683 +vn 0.8169 0.4807 -0.3186 +vn 0.4904 0.7941 -0.3590 +vn 0.1631 0.9378 -0.3063 +vn -0.0147 0.9466 -0.3221 +vn 0.2430 0.9051 -0.3487 +vn 0.9255 0.3025 -0.2278 +vn 0.1051 -0.2199 0.9698 +vn 0.2956 -0.1760 0.9389 +vn -0.4334 -0.6174 0.6565 +vn -0.6386 -0.7322 0.2368 +vn 0.8167 0.5723 0.0729 +vn 0.7633 0.5808 0.2827 +vn 0.7378 0.6195 0.2679 +vn 0.7119 0.5517 0.4344 +vn 0.0598 -0.2058 0.9767 +vn 0.7024 0.4745 0.5306 +vn 0.7950 0.6066 -0.0062 +vn 0.7777 0.5889 -0.2198 +vn 0.6442 0.5257 0.5555 +vn 0.4094 -0.8238 0.3920 +vn 0.1943 -0.9403 0.2792 +vn 0.7854 -0.2832 0.5504 +vn 0.1451 0.6953 0.7038 +vn 0.8829 -0.2319 0.4083 +vn 0.5045 0.4002 0.7650 +vn 0.3746 0.2638 0.8889 +vn 0.6302 0.2322 0.7409 +vn 0.7561 -0.2232 0.6152 +vn 0.7296 0.0237 0.6835 +vn 0.5043 0.0184 0.8633 +vn 0.5466 -0.2133 0.8098 +vn 0.2163 0.2885 0.9327 +vn 0.3000 0.4229 0.8551 +vn 0.4324 0.4473 0.7829 +vn 0.5261 0.2157 0.8226 +vn 0.6630 0.5102 0.5478 +vn 0.7724 0.4615 0.4363 +vn 0.5591 0.1728 0.8108 +vn 0.2038 0.2965 0.9330 +vn 0.3312 -0.1971 0.9228 +vn 0.1905 -0.2562 0.9476 +vn 0.1800 0.1118 0.9773 +vn 0.2780 0.1091 0.9543 +vn 0.0000 0.9522 -0.3053 +vn 0.0000 0.9307 -0.3656 +vn 0.9289 0.1250 0.3486 +vn 0.6987 0.3199 0.6399 +vn 0.8025 0.2014 0.5616 +vn 0.8748 0.0048 0.4845 +vn 0.3181 -0.0215 0.9478 +vn 0.8773 0.2747 0.3935 +vn -0.7059 0.7076 -0.0322 +vn -0.6357 0.7635 -0.1140 +vn -0.8023 0.5935 0.0634 +vn -0.7681 0.6397 -0.0274 +vn -0.8542 0.5184 0.0399 +vn -0.5767 0.8093 -0.1115 +vn -0.4980 0.8491 -0.1761 +vn -0.7314 0.6796 -0.0558 +vn -0.8283 0.5476 -0.1187 +vn -0.6490 0.7537 -0.1033 +vn -0.6781 0.6996 -0.2252 +vn -0.4828 0.8397 -0.2484 +vn -0.4205 0.8898 -0.1773 +vn -0.3905 0.9041 -0.1735 +vn -0.2319 0.9528 -0.1956 +vn -0.2858 0.9128 -0.2918 +vn -0.4255 0.8084 -0.4068 +vn -0.7912 0.2639 -0.5517 +vn -0.6906 0.5537 -0.4652 +vn -0.8665 0.2713 -0.4189 +vn -0.9095 0.4116 -0.0575 +vn -0.9397 0.3219 -0.1152 +vn -0.8683 0.4856 0.1014 +vn -0.8781 0.4773 -0.0329 +vn -0.9062 0.3947 -0.1516 +vn -0.8523 0.5096 0.1178 +vn -0.8714 0.4632 0.1614 +vn -0.8630 0.4828 0.1490 +vn -0.8804 0.4310 0.1978 +vn -0.8415 0.5325 0.0914 +vn -0.3044 0.7055 -0.6400 +vn -0.8118 0.5827 0.0374 +vn -0.0460 0.9613 -0.2716 +vn -0.1135 0.9669 -0.2282 +vn -0.8487 -0.4206 0.3205 +vn -0.9200 -0.1510 0.3616 +vn -0.8126 -0.2723 0.5152 +vn -0.8040 -0.4887 0.3387 +vn -0.8563 -0.4949 0.1475 +vn -0.9155 -0.3395 0.2159 +vn -0.2315 0.6281 -0.7428 +vn -0.1169 0.6925 -0.7118 +vn -0.1087 0.7420 -0.6615 +vn -0.1243 0.8540 -0.5051 +vn -0.9817 0.0152 0.1898 +vn -0.9675 0.1856 0.1716 +vn -0.9823 0.1570 0.1024 +vn -0.4388 -0.2012 0.8758 +vn -0.7427 -0.3039 0.5967 +vn -0.6057 -0.1196 0.7866 +vn -0.7784 0.0299 0.6270 +vn -0.8499 0.0085 0.5269 +vn -0.4297 -0.0469 0.9018 +vn -0.6632 -0.0151 0.7482 +vn -0.9698 0.2049 0.1317 +vn -0.9112 0.2002 0.3601 +vn -0.1096 0.9359 -0.3347 +vn -0.3354 0.9149 -0.2244 +vn -0.1878 0.9482 -0.2560 +vn -0.9886 0.1495 0.0183 +vn -0.9882 0.0514 0.1445 +vn -0.9693 0.1281 -0.2098 +vn -0.9901 0.0628 -0.1251 +vn -0.9977 0.0610 0.0291 +vn -0.9529 -0.0037 0.3031 +vn -0.3713 -0.6227 0.6887 +vn -0.2866 -0.4133 0.8643 +vn -0.5530 -0.5145 0.6553 +vn -0.4694 -0.3007 0.8302 +vn -0.7552 -0.2058 0.6224 +vn -0.7025 -0.0488 0.7100 +vn -0.8339 0.0809 0.5459 +vn -0.7649 0.0229 0.6437 +vn -0.9440 0.1485 0.2946 +vn -0.9046 0.0535 0.4228 +vn -0.8323 -0.0162 0.5540 +vn -0.6789 -0.0150 0.7341 +vn -0.4494 -0.2263 0.8642 +vn -0.2694 -0.3353 0.9027 +vn -0.4348 -0.1517 0.8877 +vn -0.4201 -0.0782 0.9041 +vn -0.6015 -0.0503 0.7973 +vn -0.1501 -0.6904 0.7077 +vn -0.1164 -0.4732 0.8732 +vn -0.2839 -0.2446 0.9271 +vn -0.3146 -0.1462 0.9379 +vn -0.5181 -0.0168 0.8551 +vn -0.1152 -0.3949 0.9114 +vn -0.6595 -0.0613 0.7492 +vn -0.9287 0.3149 0.1955 +vn -0.9313 0.3608 0.0501 +vn -0.9048 0.3949 0.1595 +vn -0.9014 0.3750 0.2165 +vn -0.8797 0.4214 0.2202 +vn -0.8851 0.2334 0.4025 +vn -0.8820 0.1229 0.4550 +vn -0.8373 0.2477 0.4874 +vn -0.8366 0.3992 0.3751 +vn -0.8593 0.4531 0.2371 +vn -0.8576 0.4722 0.2040 +vn -0.9692 0.2457 -0.0166 +vn -0.9461 0.2521 -0.2031 +vn -0.9523 0.2275 0.2032 +vn -0.4021 -0.0974 0.9104 +vn -0.5210 -0.3211 0.7908 +vn -0.1151 0.6577 -0.7444 +vn -0.4285 0.5814 -0.6916 +vn -0.4617 0.5793 -0.6717 +vn -0.2339 0.6816 -0.6933 +vn -0.4172 0.6038 -0.6792 +vn -0.6523 0.4847 -0.5827 +vn -0.6387 0.4890 -0.5940 +vn -0.4307 0.0884 0.8981 +vn -0.5712 0.0384 0.8199 +vn -0.4774 0.0248 0.8783 +vn -0.4777 0.0112 0.8784 +vn -0.4669 0.0288 0.8838 +vn -0.4838 0.0396 0.8743 +vn -0.1588 -0.1046 0.9817 +vn -0.6421 0.4812 -0.5968 +vn -0.6800 -0.2022 0.7048 +vn -0.7889 0.6009 0.1285 +vn -0.8520 0.2315 0.4695 +vn -0.8839 0.3512 0.3088 +vn -0.7729 -0.2160 0.5966 +vn -0.6659 -0.3040 0.6813 +vn -0.8612 0.4930 0.1238 +vn -0.5331 -0.5695 0.6257 +vn -0.3330 -0.7530 0.5676 +vn -0.4542 -0.8054 0.3807 +vn -0.7552 -0.4812 0.4450 +vn -0.4200 -0.5970 0.6835 +vn -0.2127 -0.9350 0.2839 +vn -0.3735 -0.7946 0.4786 +vn -0.6184 -0.4279 0.6591 +vn -0.4933 -0.6437 0.5850 +vn -0.2353 -0.8777 0.4173 +vn -0.0752 -0.8151 0.5743 +vn -0.3490 -0.7891 0.5054 +vn -0.6449 -0.3262 0.6911 +vn -0.0581 -0.8120 0.5807 +vn -0.2116 -0.5791 0.7873 +vn -0.3882 -0.8220 0.4168 +vn -0.9406 0.1468 0.3061 +vn -0.7479 -0.0185 0.6635 +vn -0.8950 0.0117 0.4458 +vn -0.9780 0.1085 0.1780 +vn -0.9510 0.1431 0.2742 +vn -0.8441 0.0301 0.5353 +vn -0.9687 0.2466 0.0291 +vn -0.9705 -0.0643 0.2322 +vn -0.8168 0.4242 -0.3909 +vn -0.7787 0.3464 -0.5230 +vn -0.9531 0.2824 -0.1087 +vn -0.9244 0.3335 -0.1850 +vn -0.8741 0.3143 -0.3703 +vn -0.5983 -0.0150 0.8011 +vn -0.7830 0.4291 -0.4502 +vn -0.9053 0.2115 -0.3683 +vn -0.9208 0.2272 -0.3169 +vn -0.9318 0.1382 -0.3357 +vn -0.8831 0.2428 -0.4013 +vn -0.9722 0.2253 -0.0634 +vn -0.9114 0.3310 -0.2444 +vn -0.9684 0.1733 -0.1790 +vn -0.8645 0.4382 -0.2462 +vn -0.9074 0.4047 -0.1133 +vn -0.8582 0.4951 -0.1352 +vn -0.8663 0.4978 -0.0414 +vn -0.9147 0.3174 -0.2500 +vn -0.9302 0.3481 -0.1165 +vn -0.8986 0.4386 0.0050 +vn -0.9031 0.4260 0.0543 +vn -0.7794 0.5968 -0.1906 +vn -0.7902 0.6029 -0.1098 +vn -0.6754 0.6828 -0.2786 +vn -0.6952 0.6997 -0.1643 +vn -0.9178 0.3969 0.0090 +vn -0.9554 0.2131 -0.2045 +vn -0.8072 0.4986 0.3157 +vn -0.7341 0.4555 0.5036 +vn -0.7105 0.2149 0.6701 +vn -0.9315 0.2916 -0.2175 +vn -0.8877 0.4345 0.1524 +vn -0.9487 0.2876 -0.1314 +vn -0.8917 0.4422 -0.0963 +vn -0.8120 0.5513 0.1917 +vn -0.7828 0.5446 -0.3011 +vn -0.1183 0.9398 -0.3205 +vn -0.2795 0.9021 -0.3286 +vn -0.5719 0.7507 -0.3305 +vn -0.4152 0.8497 -0.3249 +vn 0.0077 0.9398 -0.3416 +vn -0.5790 0.7873 -0.2117 +vn -0.4360 0.8599 -0.2655 +vn -0.5329 0.7984 -0.2803 +vn -0.1127 0.9359 -0.3336 +vn -0.2661 0.9086 -0.3218 +vn 0.0241 0.9474 -0.3190 +vn -0.1453 0.8028 0.5783 +vn -0.2860 0.9123 -0.2932 +vn -0.2215 -0.9014 0.3721 +vn -0.2910 -0.9505 0.1088 +vn -0.4541 -0.8865 -0.0888 +vn -0.4539 -0.7841 0.4231 +vn -0.4747 -0.8284 0.2974 +vn -0.3417 -0.9398 -0.0039 +vn -0.3639 -0.9313 0.0138 +vn -0.5307 -0.8475 0.0109 +vn -0.5758 -0.8148 -0.0674 +vn -0.7378 -0.6627 0.1281 +vn -0.7414 -0.6316 0.2264 +vn -0.6988 -0.6707 0.2484 +vn -0.5995 -0.7993 -0.0413 +vn -0.7790 -0.5758 0.2481 +vn -0.6796 -0.6033 0.4174 +vn -0.7539 -0.6522 -0.0791 +vn -0.6335 -0.7432 -0.2151 +vn -0.5549 -0.7879 -0.2670 +vn -0.6787 -0.6941 -0.2398 +vn -0.4272 -0.6470 0.6315 +vn -0.6690 -0.7392 0.0782 +vn -0.6450 -0.7393 -0.1933 +vn -0.6526 -0.7250 0.2200 +vn -0.6637 -0.7033 0.2546 +vn -0.6752 -0.6618 0.3258 +vn -0.5907 -0.8061 -0.0337 +vn -0.4101 -0.8999 0.1479 +vn 0.0591 -0.9216 0.3836 +vn -0.4336 -0.6107 0.6626 +vn -0.8471 0.0249 0.5308 +vn 0.5876 -0.8091 -0.0029 +vn 0.4120 -0.9109 -0.0211 +vn 0.3905 -0.9192 0.0502 +vn 0.0370 -0.9963 0.0773 +vn 0.5271 -0.8279 0.1915 +vn 0.2296 -0.7259 0.6483 +vn -0.1375 -0.9904 0.0145 +vn -0.6728 -0.7365 -0.0689 +vn -0.6745 -0.7374 -0.0352 +vn -0.5535 -0.8323 -0.0281 +vn -0.5839 -0.8113 0.0267 +vn -0.2070 0.9766 0.0584 +vn -0.1210 0.9661 0.2280 +vn -0.7356 -0.5047 0.4518 +vn -0.6403 -0.4551 0.6188 +vn -0.7129 -0.7013 0.0015 +vn -0.7922 -0.6049 0.0802 +vn -0.4436 -0.4072 0.7983 +vn -0.7190 -0.5740 0.3917 +vn -0.7946 -0.4053 0.4520 +vn -0.9241 -0.3797 0.0434 +vn -0.7897 -0.6080 -0.0819 +vn -0.9472 -0.2160 0.2369 +vn -0.9574 -0.1484 0.2476 +vn -0.9469 0.1744 0.2701 +vn -0.9487 0.0461 0.3128 +vn -0.5952 -0.7782 -0.2001 +vn -0.9217 -0.3671 0.1254 +vn -0.9175 -0.0637 0.3925 +vn -0.6530 -0.1609 0.7401 +vn -0.1650 -0.2144 0.9627 +vn -0.2282 -0.1237 0.9657 +vn -0.1339 -0.3113 0.9408 +vn -0.3126 -0.0507 0.9485 +vn -0.7069 -0.4240 0.5661 +vn -0.3943 -0.1053 0.9129 +vn -0.3297 0.8623 0.3844 +vn -0.6529 0.6402 0.4046 +vn -0.4427 0.8598 0.2544 +vn -0.5408 0.7346 0.4096 +vn -0.0544 0.7486 0.6607 +vn -0.0973 0.7923 0.6023 +vn -0.0391 0.7548 0.6548 +vn -0.5399 0.6954 0.4742 +vn -0.3280 0.8128 0.4814 +vn -0.2897 0.8387 0.4611 +vn -0.3706 0.8045 0.4640 +vn -0.6878 0.6725 0.2730 +vn -0.5425 0.8259 0.1535 +vn -0.1771 0.8686 0.4628 +vn -0.1948 0.8221 0.5349 +vn -0.0406 0.8713 0.4891 +vn 0.0286 0.8260 0.5630 +vn -0.2701 0.8282 0.4910 +vn -0.3648 0.7150 0.5964 +vn -0.1674 0.7658 0.6208 +vn -0.2275 0.9336 0.2769 +vn -0.1373 0.7886 0.5993 +vn -0.2347 0.8377 0.4931 +vn -0.0508 0.9140 0.4025 +vn -0.5524 0.7610 0.3402 +vn -0.1573 0.8092 0.5661 +vn -0.3077 0.7807 0.5438 +vn -0.6013 0.3955 0.6942 +vn -0.6287 0.7652 0.1383 +vn -0.5817 0.7783 0.2364 +vn -0.3233 0.9463 -0.0063 +vn -0.8911 0.1947 0.4099 +vn -0.9278 0.2681 0.2593 +vn -0.8861 0.2194 0.4082 +vn -0.9075 0.2593 0.3305 +vn -0.9191 0.0142 0.3937 +vn -0.8917 0.3740 0.2550 +vn -0.8385 0.4824 0.2531 +vn -0.7946 0.5452 0.2670 +vn -0.6667 0.6732 0.3198 +vn -0.6097 0.7107 0.3508 +vn -0.7592 0.6035 0.2436 +vn -0.8376 0.2998 0.4567 +vn -0.9043 0.3841 0.1862 +vn -0.5091 0.7868 0.3488 +vn -0.4816 0.8027 0.3518 +vn -0.3890 0.8594 0.3317 +vn -0.2983 0.9298 0.2153 +vn -0.5218 0.8276 0.2066 +vn -0.8208 -0.4093 0.3984 +vn -0.8232 -0.4819 0.3000 +vn -0.7013 -0.4134 0.5807 +vn -0.8887 -0.3870 0.2459 +vn -0.0638 -0.8465 0.5286 +vn -0.6125 -0.5175 0.5974 +vn -0.3178 -0.8795 0.3541 +vn -0.3089 -0.3165 0.8968 +vn -0.5006 -0.3766 0.7794 +vn -0.4073 -0.4945 0.7678 +vn -0.2616 -0.4242 0.8669 +vn -0.9622 -0.2691 0.0419 +vn -0.8847 -0.4660 0.0127 +vn -0.9122 -0.3857 0.1382 +vn -0.9813 -0.1799 0.0684 +vn -0.9362 -0.3495 0.0349 +vn -0.9846 -0.1733 -0.0213 +vn -0.9972 -0.0120 -0.0731 +vn -0.4913 -0.8704 0.0309 +vn 0.0114 -0.7285 0.6849 +vn -0.4826 0.5794 -0.6568 +vn -0.0873 0.6950 -0.7136 +vn -0.3205 0.6668 -0.6727 +vn 0.0052 0.9246 -0.3807 +vn -0.0287 0.8215 -0.5694 +vn -0.2424 0.7700 -0.5901 +vn -0.2991 0.7342 -0.6094 +vn -0.4485 0.6475 -0.6161 +vn -0.7361 0.4303 -0.5224 +vn -0.5987 0.5393 -0.5922 +vn -0.5971 0.5128 -0.6168 +vn -0.4266 0.6195 -0.6589 +vn -0.4452 0.4876 0.7510 +vn -0.1506 -0.0185 0.9884 +vn -0.1653 0.8188 0.5497 +vn -0.4475 0.7766 -0.4433 +vn -0.7606 0.5641 -0.3212 +vn 0.0554 -0.6311 0.7737 +vn -0.1322 0.9488 -0.2868 +vn -0.4447 0.5940 -0.6703 +vn -0.1107 0.6983 -0.7071 +vn -0.8314 -0.5344 0.1523 +vn -0.9199 -0.3919 0.0147 +vn -0.7619 -0.6435 -0.0731 +vn -0.6084 -0.7477 0.2658 +vn -0.9365 -0.3211 0.1408 +vn -0.6753 -0.6820 -0.2809 +vn -0.9498 -0.3017 0.0823 +vn -0.7473 -0.6224 -0.2326 +vn -0.8014 -0.5906 -0.0940 +vn -0.8081 -0.5888 -0.0180 +vn -0.6004 -0.7907 -0.1198 +vn -0.6069 -0.7272 -0.3207 +vn -0.6403 -0.7583 -0.1223 +vn -0.5925 -0.8006 -0.0893 +vn -0.8396 -0.5422 0.0318 +vn -0.7797 -0.5966 0.1902 +vn -0.5201 -0.8233 -0.2271 +vn -0.5200 -0.8313 -0.1961 +vn -0.9554 -0.1037 0.2764 +vn -0.9369 -0.2676 0.2250 +vn -0.8307 0.4781 -0.2849 +vn -0.6072 0.6367 -0.4752 +vn -0.8983 0.4226 -0.1201 +vn -0.6796 0.5814 0.4474 +vn -0.5966 0.4121 0.6886 +vn -0.3132 0.3367 0.8879 +vn 0.1817 -0.3441 0.9211 +vn 0.2885 0.3980 0.8708 +vn -0.3183 0.9411 -0.1140 +vn 0.7455 0.6504 0.1451 +vn -0.8340 0.2959 -0.4656 +vn -0.7598 0.6100 0.2247 +vn -0.6675 0.7420 0.0620 +vn -0.2535 0.7562 0.6033 +vn -0.6883 0.7253 -0.0098 +vn -0.8986 0.4383 0.0193 +vn -0.2416 0.9129 0.3290 +vn -0.5995 0.7955 0.0878 +vn -0.9176 0.2927 -0.2688 +vn -0.9459 0.2254 -0.2332 +vn -0.7449 0.4434 -0.4985 +vn -0.9625 0.2677 -0.0443 +vn -0.9719 0.1790 -0.1529 +vn -0.9783 0.2042 -0.0339 +vn -0.9405 0.2532 -0.2264 +vn -0.9666 0.2521 -0.0460 +vn -0.8474 0.3321 -0.4141 +vn -0.9066 0.4118 0.0924 +vn -0.9817 0.1865 0.0376 +vn -0.3380 0.4837 0.8073 +vn -0.6411 0.7674 -0.0125 +vn -0.7683 0.6032 0.2142 +vn -0.8184 0.5578 0.1378 +vn -0.8528 -0.0475 0.5199 +vn -0.7239 -0.4853 0.4904 +vn -0.4044 -0.4647 0.7877 +vn -0.7184 -0.6696 -0.1881 +vn -0.9473 -0.1775 0.2666 +vn -0.6623 -0.1268 0.7384 +vn -0.8178 -0.4696 0.3327 +vn -0.6245 0.0725 0.7777 +vn -0.2344 -0.0113 0.9721 +vn -0.4046 -0.2462 0.8807 +vn -0.3941 -0.8863 0.2429 +vn -0.6654 -0.1179 0.7371 +vn -0.6627 -0.6709 0.3325 +vn -0.7925 -0.5763 0.1993 +vn -0.8707 -0.3982 0.2886 +vn -0.8432 0.1794 0.5067 +vn -0.9914 -0.0684 0.1112 +vn -0.3310 -0.8962 0.2952 +vn -0.7978 -0.5037 -0.3312 +vn -0.3774 0.0584 0.9242 +vn -0.6472 -0.7452 0.1606 +vn -0.3627 -0.2486 0.8981 +vn -0.4023 0.2092 0.8913 +vn -0.6513 -0.5982 0.4668 +vn -0.6491 -0.7569 -0.0761 +vn -0.3436 -0.9263 -0.1543 +vn -0.3031 -0.3053 0.9027 +vn -0.9206 -0.3901 -0.0167 +vn -0.8311 -0.5432 -0.1189 +vn -0.9915 -0.0196 -0.1286 +vn -0.7888 0.5757 -0.2155 +vn -0.6801 0.6856 -0.2596 +vn -0.6355 0.7363 -0.2323 +vn -0.6877 0.6899 -0.2261 +vn -0.9212 0.3332 -0.2008 +vn -0.8088 0.5431 -0.2253 +vn -0.9046 0.3909 -0.1695 +vn -0.9842 -0.0016 -0.1771 +vn -0.9356 -0.3091 -0.1704 +vn -0.3587 0.8872 -0.2900 +vn -0.4302 0.8473 -0.3115 +vn -0.2358 -0.9711 -0.0360 +vn -0.4000 0.8422 -0.3614 +vn -0.3005 0.8741 -0.3815 +vn -0.6170 -0.7814 -0.0933 +vn -0.9627 0.2689 0.0296 +vn -0.9784 -0.1214 -0.1670 +vn -0.8206 0.1611 0.5484 +vn -0.4889 0.5419 0.6835 +vn -0.4367 0.5770 0.6902 +vn -0.3110 0.6448 0.6982 +vn -0.8897 0.1521 0.4303 +vn -0.8677 0.4937 -0.0576 +vn -0.6927 0.4663 0.5501 +vn -0.6946 -0.7098 -0.1169 +vn -0.2319 0.5500 0.8023 +vn -0.1266 0.3410 0.9315 +vn -0.3837 0.6668 0.6388 +vn -0.2640 0.5331 0.8038 +vn -0.4053 -0.8439 0.3515 +vn -0.5154 -0.7365 0.4380 +vn -0.7890 -0.3247 0.5216 +vn -0.4592 -0.8796 0.1242 +vn -0.5531 0.2388 0.7982 +vn -0.4424 0.6411 0.6271 +vn -0.7139 0.5820 0.3892 +vn -0.6139 0.7535 0.2351 +vn -0.5107 0.7719 0.3785 +vn -0.3461 0.9357 -0.0680 +vn -0.5485 0.8319 -0.0840 +vn -0.2163 0.9236 0.3164 +vn -0.5256 0.6211 0.5813 +vn 0.0284 0.8238 0.5661 +vn -0.6204 0.3302 0.7114 +vn -0.6146 0.7541 0.2315 +vn -0.8864 0.2323 0.4003 +vn -0.8134 -0.1635 0.5582 +vn 0.0352 0.7168 0.6964 +vn -0.6129 0.1742 0.7707 +vn -0.8856 -0.3421 0.3141 +vn -0.7799 0.6251 0.0307 +vn -0.9556 0.2855 0.0728 +vn -0.7306 0.6776 -0.0836 +vn -0.8365 -0.2363 0.4944 +vn -0.9903 0.0976 0.0989 +vn -0.8423 -0.3548 0.4057 +vn -0.0187 0.5722 0.8199 +vn -0.3393 0.4586 0.8213 +vn 0.0167 0.5616 0.8272 +vn -0.6146 0.3960 0.6822 +vn -0.6486 0.6336 0.4216 +vn -0.8307 0.1838 0.5255 +vn -0.7956 0.4235 0.4331 +vn -0.9330 0.0583 0.3550 +vn -0.8480 0.4299 0.3098 +vn 0.3781 0.8724 0.3098 +vn -0.9247 -0.0047 0.3806 +vn -0.9819 -0.0545 0.1814 +vn -0.9698 0.0264 0.2425 +vn -0.7741 0.0154 0.6329 +vn -0.7346 0.1909 0.6511 +vn -0.7382 0.3495 0.5769 +vn -0.9730 0.1491 0.1763 +vn -0.9518 -0.2485 0.1799 +vn -0.6135 0.4266 0.6645 +vn -0.8621 -0.2613 0.4340 +vn -0.9306 0.2062 0.3024 +vn -0.9051 0.3038 0.2973 +vn -0.7945 0.3432 0.5010 +vn -0.9755 -0.0135 0.2194 +vn -0.9807 -0.0365 0.1919 +vn -0.8177 0.5610 0.1290 +vn 0.2113 0.7844 -0.5831 +vn 0.1888 0.6806 -0.7079 +vn 0.7326 0.2914 -0.6151 +vn 0.5543 0.5818 -0.5951 +vn 0.6364 0.6131 -0.4681 +vn 0.5883 0.5293 -0.6114 +vn 0.6942 0.5031 -0.5147 +vn -0.0225 -0.9240 0.3816 +vn 0.0228 -0.9940 0.1071 +vn -0.4109 -0.6906 0.5951 +vn 0.1348 -0.9391 0.3161 +vn -0.9079 -0.3681 -0.2006 +vn -0.8402 -0.3101 -0.4448 +vn 0.0091 -0.9008 -0.4340 +vn -0.3562 0.8682 0.3453 +vn -0.4772 0.7221 0.5008 +vn -0.2477 0.8641 0.4381 +vn -0.1782 0.7414 0.6470 +vn -0.2818 0.7820 0.5559 +vn -0.7809 0.1180 -0.6134 +vn -0.8390 0.4802 -0.2559 +vn -0.4193 0.3136 -0.8520 +vn 0.6367 -0.7637 -0.1062 +vn -0.1803 -0.9775 -0.1092 +vn -0.7925 -0.5757 0.2011 +vn -0.9715 0.1908 -0.1407 +vn 0.1442 -0.7067 -0.6926 +vn -0.9351 0.2828 -0.2133 +vn -0.7533 -0.1436 -0.6418 +vn 0.5709 -0.6130 -0.5461 +vn 0.0108 -0.4275 -0.9039 +vn 0.4322 -0.6225 -0.6524 +vn -0.6813 -0.0624 -0.7293 +vn -0.9005 0.4082 -0.1500 +vn 0.5434 -0.8358 0.0783 +vn -0.3552 -0.9344 -0.0245 +vn -0.9648 0.2568 0.0572 +vn -0.7491 0.6624 0.0002 +vn -0.4278 0.8934 -0.1371 +vn -0.1563 0.9459 -0.2843 +vn -0.3214 0.9118 -0.2554 +vn -0.0959 0.9361 -0.3383 +vn -0.1492 0.9253 -0.3485 +vn -0.1048 0.9535 -0.2825 +vn -0.1034 0.9865 -0.1266 +vn -0.6554 0.7533 -0.0540 +vn -0.7269 0.6845 0.0562 +vn -0.0607 0.9937 -0.0947 +vn -0.0824 0.8422 -0.5327 +vn -0.1064 0.9344 -0.3398 +vn -0.1271 0.8181 -0.5608 +vn -0.1343 0.7598 -0.6361 +vn -0.1275 0.8791 -0.4592 +vn -0.2860 0.3995 0.8709 +vn -0.3702 0.8440 0.3880 +vn -0.6809 0.7318 0.0284 +vn -0.5214 0.3315 0.7862 +vn -0.7797 0.0205 0.6258 +vn -0.8988 0.1980 0.3911 +vn -0.9998 0.0169 -0.0088 +vn -0.8753 -0.4614 0.1448 +vn -0.5594 -0.3754 0.7389 +vn -0.8035 -0.4675 0.3686 +vn -0.7306 0.6736 0.1115 +vn -0.8615 0.4649 0.2041 +vn -0.7936 0.5992 0.1055 +vn -0.6894 0.7235 -0.0338 +vn -0.9436 0.3209 0.0814 +vn -0.6370 0.6007 0.4830 +vn -0.5840 0.7763 0.2371 +vn -0.5821 0.6321 0.5115 +vn -0.6413 0.7254 0.2499 +vn -0.7255 0.6795 0.1091 +vn -0.6774 0.6272 0.3841 +vn -0.7980 0.4978 0.3396 +vn -0.5673 0.7513 0.3371 +vn -0.6166 0.7799 0.1071 +vn -0.6605 0.7497 -0.0411 +vn -0.7075 0.6984 0.1081 +vn -0.6471 0.7623 0.0080 +vn -0.7881 0.6151 0.0222 +vn -0.6285 0.7776 -0.0189 +vn -0.6557 0.6499 0.3843 +vn -0.6221 0.3303 0.7099 +vn -0.5773 0.0689 0.8136 +vn -0.5936 0.4450 0.6705 +vn -0.5380 0.3140 0.7823 +vn -0.6726 0.5151 0.5313 +vn -0.7511 0.4060 0.5205 +vn -0.7360 0.2819 0.6154 +vn -0.4705 0.1532 0.8690 +vn -0.5694 0.4761 0.6702 +vn -0.6115 0.3881 0.6895 +vn 0.4454 -0.7530 -0.4844 +vn 0.4686 -0.7518 -0.4638 +vn 0.5138 -0.7761 -0.3655 +vn -0.4306 -0.1322 -0.8928 +vn -0.0214 -0.8707 -0.4914 +vn -0.2848 0.1867 -0.9402 +vn 0.2695 -0.7941 -0.5447 +vn 0.3168 -0.8032 -0.5044 +vn 0.4856 -0.7575 -0.4363 +vn 0.5963 -0.7069 -0.3803 +vn 0.6596 -0.6565 -0.3658 +vn 0.1672 0.5252 -0.8343 +vn 0.3582 -0.8316 -0.4243 +vn 0.1722 -0.8703 -0.4613 +vn 0.3603 -0.8984 -0.2512 +vn 0.2437 -0.9246 -0.2926 +vn -0.1741 0.3336 -0.9265 +vn -0.5544 0.8321 -0.0111 +vn -0.6128 0.7461 -0.2604 +vn -0.5478 0.8355 -0.0428 +vn 0.1303 0.2501 -0.9594 +vn 0.6904 -0.6778 -0.2525 +vn -0.7308 0.6550 -0.1923 +vn -0.7163 0.6300 -0.2999 +vn 0.4748 -0.7779 -0.4116 +vn 0.4768 -0.8271 -0.2974 +vn 0.5966 -0.7469 -0.2934 +vn 0.3843 -0.9218 0.0516 +vn 0.4618 -0.8723 -0.1606 +vn 0.5757 -0.8162 0.0473 +vn 0.5638 -0.7641 -0.3136 +vn 0.4960 -0.8090 -0.3152 +vn 0.3789 -0.9078 -0.1795 +vn 0.3430 -0.9386 -0.0368 +vn 0.0427 -0.9160 0.3990 +vn 0.6585 -0.7402 -0.1358 +vn 0.6635 -0.7405 -0.1067 +vn 0.5882 -0.8083 0.0258 +vn 0.7074 -0.6845 -0.1761 +vn 0.6970 -0.6774 -0.2353 +vn 0.7363 -0.6508 -0.1851 +vn 0.5178 -0.6417 -0.5657 +vn 0.0610 -0.0703 -0.9956 +vn 0.7489 -0.6311 -0.2022 +vn 0.6920 -0.6618 -0.2883 +vn 0.4655 -0.8805 -0.0896 +vn 0.4585 -0.8863 0.0646 +vn 0.6013 -0.7824 -0.1620 +vn 0.5509 -0.8344 -0.0180 +vn 0.4767 -0.8722 0.1095 +vn -0.2485 -0.4421 0.8618 +vn -0.3902 -0.5499 0.7385 +vn 0.1415 -0.9310 0.3364 +vn -0.2979 -0.5561 0.7759 +vn -0.1032 -0.3584 0.9278 +vn -0.6807 0.0086 0.7325 +vn 0.2022 -0.8778 0.4342 +vn 0.3601 -0.7574 0.5446 +vn -0.7168 -0.6941 -0.0655 +vn -0.9076 -0.3858 -0.1656 +vn -0.4872 -0.8705 -0.0692 +vn -0.4793 -0.8759 -0.0547 +vn -0.9034 -0.4161 -0.1036 +vn -0.9860 -0.0183 -0.1658 +vn -0.9855 -0.0144 -0.1691 +vn -0.8838 -0.4357 -0.1702 +vn -0.9690 0.0865 -0.2314 +vn -0.4948 -0.8608 -0.1186 +vn -0.9638 0.2101 -0.1640 +vn -0.9060 0.3591 -0.2240 +vn -0.6978 -0.7154 -0.0353 +vn -0.5210 -0.8536 0.0014 +vn -0.3106 -0.9481 -0.0681 +vn -0.2962 -0.9533 -0.0587 +vn -0.2585 -0.9566 -0.1342 +vn -0.8244 0.5077 -0.2501 +vn -0.7755 0.5705 -0.2701 +vn -0.9092 0.3399 -0.2403 +vn -0.8226 0.4944 -0.2808 +vn -0.7688 0.5621 -0.3050 +vn -0.8999 0.3805 -0.2129 +vn -0.6580 0.6858 -0.3107 +vn -0.6344 0.6929 -0.3426 +vn -0.0027 -0.9989 -0.0462 +vn 0.3967 -0.9055 -0.1502 +vn 0.1408 -0.9482 -0.2846 +vn 0.3984 -0.9109 -0.1075 +vn 0.4898 -0.8480 -0.2023 +vn -0.5215 -0.6521 -0.5502 +vn -0.2160 -0.9619 -0.1676 +vn -0.7384 -0.5815 -0.3415 +vn -0.4740 -0.5862 -0.6570 +vn -0.5952 -0.8033 0.0196 +vn -0.5066 -0.8526 0.1282 +vn -0.0475 -0.9987 -0.0155 +vn 0.6097 -0.7869 -0.0950 +vn 0.0200 -0.9346 -0.3552 +vn -0.5264 -0.4328 -0.7318 +vn 0.5377 -0.7964 -0.2767 +vn -0.2820 -0.9593 0.0147 +vn -0.3015 -0.9523 0.0457 +vn -0.5136 -0.8549 0.0730 +vn -0.5256 -0.8354 0.1604 +vn -0.2954 -0.9554 0.0021 +vn -0.6541 -0.7507 0.0925 +vn -0.3396 -0.9386 0.0607 +vn -0.5560 -0.8230 0.1165 +vn -0.6385 -0.7633 0.0979 +vn 0.5616 -0.6806 -0.4705 +vn -0.4348 -0.9004 0.0145 +vn -0.2035 -0.9742 -0.0977 +vn -0.5067 -0.8411 -0.1892 +vn -0.2936 -0.9084 -0.2976 +vn -0.0466 -0.9677 -0.2477 +vn -0.1606 -0.9153 -0.3693 +vn -0.7745 -0.6234 0.1070 +vn -0.1805 -0.9444 -0.2748 +vn 0.3090 0.8467 -0.4331 +vn 0.4933 0.7294 -0.4740 +vn 0.3111 0.8824 -0.3530 +vn 0.5697 0.7401 -0.3573 +vn 0.6647 -0.5935 -0.4538 +vn -0.5865 -0.7831 -0.2065 +vn 0.7742 -0.6228 -0.1126 +vn 0.7627 -0.5859 -0.2736 +vn -0.8828 -0.1119 0.4562 +vn -0.6617 -0.5839 0.4703 +vn -0.9473 0.2579 0.1898 +vn -0.8999 0.1347 0.4148 +vn -0.4892 -0.6321 0.6009 +vn -0.3381 -0.9071 -0.2507 +vn 0.0748 0.9274 -0.3664 +vn -0.6447 0.7620 -0.0596 +vn -0.8459 0.5334 -0.0067 +vn -0.7866 0.6002 -0.1449 +vn -0.8891 0.4575 0.0140 +vn -0.8556 0.4886 -0.1709 +vn -0.9044 0.4238 0.0484 +vn -0.9231 0.3500 -0.1591 +vn -0.3221 0.9256 -0.1989 +vn -0.9931 0.0297 0.1136 +vn 0.4494 0.8382 -0.3089 +vn -0.1155 0.9711 -0.2088 +vn 0.1446 0.9568 -0.2523 +vn -0.2433 0.9148 -0.3224 +vn -0.0545 0.9359 -0.3481 +vn -0.3437 0.8892 -0.3020 +vn -0.9229 0.3836 0.0308 +vn -0.7925 -0.1060 0.6005 +vn -0.8750 0.3163 0.3664 +vn -0.7456 -0.0547 0.6641 +vn -0.4041 -0.5988 0.6914 +vn -0.9055 0.3787 0.1915 +vn -0.8642 0.4711 0.1765 +vn -0.8236 0.2401 0.5139 +vn 0.1752 -0.9173 0.3576 +vn 0.6876 -0.7255 -0.0311 +vn 0.1272 -0.9468 0.2954 +vn -0.6752 0.6728 -0.3021 +vn -0.8335 0.5469 -0.0786 +vn -0.7098 0.7042 -0.0143 +vn 0.7171 -0.6260 -0.3062 +vn -0.8611 0.5077 0.0250 +vn 0.7182 -0.6438 -0.2638 +vn 0.7851 -0.5962 -0.1679 +vn -0.6044 0.7966 0.0119 +vn 0.3138 -0.9344 0.1687 +vn -0.5591 0.1728 0.8108 +vn -0.5261 0.2157 0.8226 +vn -0.5282 0.2889 0.7985 +vn -0.4435 0.5161 0.7327 +vn -0.4324 0.4473 0.7829 +vn -0.3000 0.4229 0.8551 +vn -0.6719 0.1825 0.7178 +vn -0.3627 0.6289 0.6877 +vn -0.1943 -0.9403 0.2792 +vn -0.2571 -0.9026 0.3453 +vn -0.1451 0.6953 0.7038 +vn -0.1945 0.7453 0.6377 +vn -0.8677 0.4605 0.1872 +vn -0.9499 0.2258 0.2161 +vn -0.9585 0.2850 -0.0041 +vn -0.7658 0.1108 0.6334 +vn -0.8220 0.3556 0.4448 +vn -0.8462 0.2304 0.4805 +vn -0.8489 0.3315 0.4116 +vn -0.7219 0.4261 0.5452 +vn -0.9842 0.0645 0.1647 +vn -0.9774 0.1594 0.1386 +vn -0.9642 0.1428 0.2234 +vn -0.9335 0.1669 0.3172 +vn -0.9508 0.3093 -0.0180 +vn -0.9969 0.0713 -0.0333 +vn -0.8223 0.4848 0.2981 +vn -0.9954 0.0240 0.0928 +vn -0.9902 0.1357 -0.0312 +vn -0.5298 0.4357 0.7277 +vn -0.5045 0.4002 0.7650 +vn -0.6630 0.5102 0.5478 +vn -0.3746 0.2638 0.8889 +vn -0.2163 0.2885 0.9327 +vn -0.8997 0.3933 0.1896 +vn -0.7724 0.4615 0.4363 +vn -0.5842 -0.7029 0.4058 +vn -0.9550 -0.0469 0.2929 +vn -0.9289 0.1250 0.3486 +vn -0.9865 -0.1241 0.1069 +vn -0.9883 0.0350 0.1487 +vn -0.8748 0.0048 0.4845 +vn -0.8025 0.2014 0.5616 +vn -0.6302 0.2322 0.7409 +vn -0.6987 0.3199 0.6399 +vn -0.7296 0.0237 0.6835 +vn -0.8829 -0.2319 0.4082 +vn -0.7561 -0.2232 0.6152 +vn -0.9368 -0.2559 0.2386 +vn -0.3312 -0.1971 0.9228 +vn -0.3181 -0.0215 0.9478 +vn -0.5466 -0.2133 0.8098 +vn -0.8773 0.2747 0.3935 +vn -0.9660 0.2205 0.1349 +vn -0.1800 0.1118 0.9773 +vn -0.2780 0.1091 0.9543 +vn -0.5043 0.0184 0.8633 +vn -0.4094 -0.8238 0.3920 +vn -0.7074 -0.4736 0.5245 +vn -0.7854 -0.2832 0.5504 +vn -0.5533 -0.7629 0.3342 +vn -0.6256 -0.7676 -0.1388 +vn -0.6592 -0.7458 0.0957 +vn -0.3082 -0.9439 -0.1183 +vn -0.4920 -0.8657 -0.0925 +vn -0.9071 0.4060 0.1109 +vn -0.7567 0.6344 0.1578 +vn -0.8940 0.0804 0.4407 +vn -0.9163 0.1617 0.3663 +vn -0.9204 0.0081 0.3908 +vn -0.7013 -0.6624 0.2633 +vn -0.7124 -0.5826 0.3912 +vn -0.1542 -0.9038 0.3991 +vn -0.2249 -0.9441 0.2411 +vn -0.3896 -0.9016 0.1877 +vn -0.5230 -0.8436 0.1216 +vn -0.2956 -0.1760 0.9389 +vn -0.0598 -0.2058 0.9767 +vn -0.7024 0.4745 0.5306 +vn -0.1051 -0.2199 0.9698 +vn -0.7633 0.5808 0.2827 +vn -0.8167 0.5723 0.0729 +vn -0.7378 0.6195 0.2679 +vn -0.7119 0.5517 0.4344 +vn 0.4334 -0.6174 0.6565 +vn 0.5847 -0.6842 0.4359 +vn 0.6898 -0.7238 -0.0145 +vn 0.6386 -0.7322 0.2368 +vn -0.8550 0.4596 -0.2401 +vn -0.7777 0.5889 -0.2198 +vn -0.7950 0.6066 -0.0062 +vn -0.6442 0.5257 0.5555 +vn 0.6699 -0.7424 0.0105 +vn 0.7158 -0.6956 0.0613 +vn -0.5315 -0.8440 0.0722 +vn -0.0779 -0.9961 0.0418 +vn 0.2225 -0.9741 0.0410 +vn 0.6927 -0.7120 0.1147 +vn -0.2038 0.2965 0.9330 +vn -0.1905 -0.2562 0.9476 +vn -0.6944 0.6186 -0.3676 +vn -0.6556 0.6745 -0.3393 +vn -0.7493 0.5698 -0.3374 +vn -0.8697 0.4143 -0.2683 +vn -0.8169 0.4807 -0.3186 +vn -0.4421 0.8381 -0.3195 +vn -0.4904 0.7941 -0.3590 +vn -0.2430 0.9051 -0.3487 +vn 0.0147 0.9466 -0.3221 +vn -0.1631 0.9378 -0.3063 +vn -0.9046 -0.1353 -0.4042 +vn -0.8851 0.0603 -0.4615 +vn -0.9438 0.0431 -0.3278 +vn -0.8822 0.2748 -0.3824 +vn -0.9232 0.1616 -0.3487 +vn -0.9751 0.0401 -0.2180 +vn -0.9480 -0.0602 -0.3124 +vn -0.9661 0.1283 -0.2240 +vn -0.7600 0.4220 -0.4942 +vn -0.4682 0.7750 -0.4243 +vn -0.9255 0.3025 -0.2278 +vn -0.9572 0.1976 -0.2113 +vn -0.9457 0.2416 -0.2173 +f 203/203/203 204/204/204 205/205/205 +f 204/204/204 206/206/206 205/205/205 +f 204/204/204 203/203/203 207/207/207 +f 206/206/206 204/204/204 208/208/208 +f 209/209/209 205/205/205 206/206/206 +f 210/210/210 211/211/211 208/208/208 +f 211/211/211 206/206/206 208/208/208 +f 203/203/203 212/212/212 207/207/207 +f 210/210/210 208/208/208 213/213/213 +f 214/214/214 215/215/215 216/216/216 +f 215/215/215 213/213/213 216/216/216 +f 213/213/213 215/215/215 210/210/210 +f 208/208/208 204/204/204 217/217/217 +f 204/204/204 207/207/207 217/217/217 +f 214/214/214 218/218/218 215/215/215 +f 219/219/219 220/220/220 210/210/210 +f 221/221/221 219/219/219 222/222/222 +f 222/222/222 223/223/223 221/221/221 +f 222/222/222 219/219/219 210/210/210 +f 224/224/224 225/225/225 223/223/223 +f 215/215/215 224/224/224 222/222/222 +f 222/222/222 210/210/210 215/215/215 +f 226/226/226 219/219/219 227/227/227 +f 209/209/209 211/211/211 228/228/228 +f 211/211/211 220/220/220 228/228/228 +f 206/206/206 211/211/211 209/209/209 +f 220/220/220 211/211/211 210/210/210 +f 219/219/219 221/221/221 227/227/227 +f 220/220/220 219/219/219 226/226/226 +f 226/226/226 228/228/228 220/220/220 +f 229/229/229 216/216/216 213/213/213 +f 230/230/230 231/231/231 232/232/232 +f 230/230/230 233/233/233 234/234/234 +f 235/235/235 236/236/236 230/230/230 +f 232/232/232 235/235/235 230/230/230 +f 235/235/235 232/232/232 218/218/218 +f 236/236/236 235/235/235 214/214/214 +f 214/214/214 216/216/216 236/236/236 +f 237/237/237 234/234/234 233/233/233 +f 238/238/238 239/239/239 240/240/240 +f 241/241/241 240/240/240 242/242/242 +f 241/241/241 243/243/243 240/240/240 +f 239/239/239 242/242/242 240/240/240 +f 231/231/231 230/230/230 244/244/244 +f 234/234/234 245/245/245 244/244/244 +f 246/246/246 247/247/247 248/248/248 +f 229/229/229 249/249/249 236/236/236 +f 216/216/216 229/229/229 236/236/236 +f 249/249/249 250/250/250 233/233/233 +f 229/229/229 208/208/208 217/217/217 +f 251/251/251 252/252/252 229/229/229 +f 252/252/252 253/253/253 229/229/229 +f 251/251/251 229/229/229 217/217/217 +f 236/236/236 249/249/249 233/233/233 +f 254/254/254 255/255/255 256/256/256 +f 233/233/233 250/250/250 237/237/237 +f 214/214/214 235/235/235 218/218/218 +f 255/255/255 237/237/237 256/256/256 +f 236/236/236 233/233/233 230/230/230 +f 256/256/256 250/250/250 249/249/249 +f 253/253/253 256/256/256 249/249/249 +f 222/222/222 224/224/224 223/223/223 +f 257/257/257 258/258/258 259/259/259 +f 260/260/260 261/261/261 262/262/262 +f 263/263/263 264/264/264 259/259/259 +f 258/258/258 257/257/257 265/265/265 +f 266/266/266 267/267/267 263/263/263 +f 268/268/268 267/267/267 266/266/266 +f 257/257/257 269/269/269 265/265/265 +f 264/264/264 270/270/270 260/260/260 +f 271/271/271 243/243/243 272/272/272 +f 272/272/272 241/241/241 261/261/261 +f 241/241/241 273/273/273 274/274/274 +f 272/272/272 260/260/260 270/270/270 +f 260/260/260 272/272/272 261/261/261 +f 260/260/260 262/262/262 257/257/257 +f 275/275/275 271/271/271 272/272/272 +f 276/276/276 277/277/277 278/278/278 +f 279/279/279 276/276/276 278/278/278 +f 277/277/277 280/280/280 281/281/281 +f 278/278/278 282/282/282 254/254/254 +f 253/253/253 279/279/279 256/256/256 +f 278/278/278 283/283/283 279/279/279 +f 278/278/278 281/281/281 282/282/282 +f 282/282/282 281/281/281 284/284/284 +f 258/258/258 268/268/268 266/266/266 +f 266/266/266 263/263/263 259/259/259 +f 258/258/258 266/266/266 259/259/259 +f 285/285/285 286/286/286 287/287/287 +f 283/283/283 278/278/278 254/254/254 +f 237/237/237 250/250/250 256/256/256 +f 230/230/230 234/234/234 244/244/244 +f 274/274/274 261/261/261 241/241/241 +f 288/288/288 289/289/289 228/228/228 +f 290/290/290 223/223/223 225/225/225 +f 290/290/290 265/265/265 223/223/223 +f 226/226/226 288/288/288 228/228/228 +f 288/288/288 291/291/291 261/261/261 +f 289/289/289 288/288/288 274/274/274 +f 274/274/274 292/292/292 289/289/289 +f 265/265/265 221/221/221 223/223/223 +f 293/293/293 224/224/224 218/218/218 +f 224/224/224 215/215/215 218/218/218 +f 225/225/225 224/224/224 293/293/293 +f 269/269/269 227/227/227 221/221/221 +f 287/287/287 265/265/265 290/290/290 +f 294/294/294 265/265/265 287/287/287 +f 221/221/221 265/265/265 269/269/269 +f 273/273/273 295/295/295 292/292/292 +f 257/257/257 262/262/262 269/269/269 +f 294/294/294 258/258/258 265/265/265 +f 274/274/274 273/273/273 292/292/292 +f 242/242/242 273/273/273 241/241/241 +f 295/295/295 273/273/273 242/242/242 +f 242/242/242 296/296/296 295/295/295 +f 264/264/264 260/260/260 257/257/257 +f 291/291/291 288/288/288 226/226/226 +f 226/226/226 227/227/227 291/291/291 +f 274/274/274 288/288/288 261/261/261 +f 262/262/262 291/291/291 227/227/227 +f 259/259/259 264/264/264 257/257/257 +f 291/291/291 262/262/262 261/261/261 +f 269/269/269 262/262/262 227/227/227 +f 238/238/238 240/240/240 243/243/243 +f 297/297/297 298/298/298 299/299/299 +f 300/300/300 301/301/301 302/302/302 +f 303/303/303 304/304/304 301/301/301 +f 305/305/305 298/298/298 297/297/297 +f 305/305/305 297/297/297 306/306/306 +f 307/307/307 308/308/308 306/306/306 +f 309/309/309 297/297/297 310/310/310 +f 300/300/300 303/303/303 301/301/301 +f 311/311/311 312/312/312 313/313/313 +f 314/314/314 313/313/313 312/312/312 +f 315/315/315 313/313/313 314/314/314 +f 316/316/316 317/317/317 311/311/311 +f 318/318/318 302/302/302 319/319/319 +f 320/320/320 300/300/300 302/302/302 +f 319/319/319 302/302/302 301/301/301 +f 321/321/321 322/322/322 323/323/323 +f 324/324/324 321/321/321 323/323/323 +f 325/325/325 323/323/323 326/326/326 +f 325/325/325 327/327/327 323/323/323 +f 328/328/328 329/329/329 330/330/330 +f 324/324/324 330/330/330 331/331/331 +f 328/328/328 324/324/324 323/323/323 +f 325/325/325 326/326/326 332/332/332 +f 308/308/308 333/333/333 305/305/305 +f 333/333/333 298/298/298 305/305/305 +f 309/309/309 306/306/306 297/297/297 +f 334/334/334 335/335/335 308/308/308 +f 308/308/308 305/305/305 306/306/306 +f 307/307/307 334/334/334 308/308/308 +f 335/335/335 333/333/333 308/308/308 +f 336/336/336 311/311/311 313/313/313 +f 337/337/337 338/338/338 339/339/339 +f 338/338/338 337/337/337 340/340/340 +f 341/341/341 342/342/342 343/343/343 +f 339/339/339 344/344/344 337/337/337 +f 345/345/345 346/346/346 347/347/347 +f 345/345/345 347/347/347 348/348/348 +f 349/349/349 345/345/345 348/348/348 +f 315/315/315 343/343/343 342/342/342 +f 350/350/350 351/351/351 352/352/352 +f 344/344/344 352/352/352 351/351/351 +f 351/351/351 337/337/337 344/344/344 +f 339/339/339 353/353/353 344/344/344 +f 342/342/342 354/354/354 315/315/315 +f 339/339/339 315/315/315 354/354/354 +f 354/354/354 353/353/353 339/339/339 +f 355/355/355 356/356/356 357/357/357 +f 358/358/358 359/359/359 360/360/360 +f 360/360/360 359/359/359 357/357/357 +f 359/359/359 355/355/355 357/357/357 +f 360/360/360 311/311/311 336/336/336 +f 336/336/336 313/313/313 315/315/315 +f 360/360/360 336/336/336 358/358/358 +f 360/360/360 357/357/357 361/361/361 +f 362/362/362 363/363/363 364/364/364 +f 364/364/364 365/365/365 366/366/366 +f 347/347/347 364/364/364 366/366/366 +f 367/367/367 368/368/368 369/369/369 +f 357/357/357 356/356/356 361/361/361 +f 370/370/370 367/367/367 371/371/371 +f 367/367/367 369/369/369 371/371/371 +f 330/330/330 324/324/324 328/328/328 +f 372/372/372 373/373/373 374/374/374 +f 372/372/372 374/374/374 375/375/375 +f 376/376/376 373/373/373 372/372/372 +f 377/377/377 378/378/378 374/374/374 +f 377/377/377 373/373/373 376/376/376 +f 376/376/376 379/379/379 377/377/377 +f 374/374/374 373/373/373 377/377/377 +f 380/380/380 379/379/379 376/376/376 +f 381/381/381 382/382/382 372/372/372 +f 383/383/383 384/384/384 381/381/381 +f 374/374/374 385/385/385 375/375/375 +f 383/383/383 381/381/381 372/372/372 +f 380/380/380 386/386/386 379/379/379 +f 376/376/376 372/372/372 382/382/382 +f 380/380/380 376/376/376 382/382/382 +f 387/387/387 388/388/388 389/389/389 +f 390/390/390 388/388/388 391/391/391 +f 391/391/391 392/392/392 393/393/393 +f 271/271/271 275/275/275 394/394/394 +f 241/241/241 272/272/272 243/243/243 +f 275/275/275 272/272/272 270/270/270 +f 243/243/243 271/271/271 394/394/394 +f 395/395/395 391/391/391 393/393/393 +f 396/396/396 395/395/395 393/393/393 +f 393/393/393 392/392/392 397/397/397 +f 398/398/398 397/397/397 399/399/399 +f 392/392/392 399/399/399 397/397/397 +f 400/400/400 390/390/390 391/391/391 +f 392/392/392 387/387/387 399/399/399 +f 387/387/387 389/389/389 399/399/399 +f 372/372/372 375/375/375 383/383/383 +f 401/401/401 402/402/402 403/403/403 +f 402/402/402 404/404/404 403/403/403 +f 405/405/405 321/321/321 324/324/324 +f 402/402/402 406/406/406 407/407/407 +f 406/406/406 402/402/402 401/401/401 +f 401/401/401 408/408/408 406/406/406 +f 404/404/404 402/402/402 407/407/407 +f 324/324/324 331/331/331 405/405/405 +f 332/332/332 326/326/326 322/322/322 +f 322/322/322 409/409/409 332/332/332 +f 322/322/322 326/326/326 323/323/323 +f 410/410/410 409/409/409 322/322/322 +f 410/410/410 321/321/321 411/411/411 +f 321/321/321 405/405/405 411/411/411 +f 322/322/322 321/321/321 410/410/410 +f 375/375/375 385/385/385 407/407/407 +f 385/385/385 412/412/412 407/407/407 +f 408/408/408 383/383/383 406/406/406 +f 413/413/413 414/414/414 412/412/412 +f 413/413/413 385/385/385 378/378/378 +f 385/385/385 374/374/374 378/378/378 +f 412/412/412 385/385/385 413/413/413 +f 406/406/406 383/383/383 375/375/375 +f 415/415/415 404/404/404 416/416/416 +f 416/416/416 417/417/417 415/415/415 +f 404/404/404 415/415/415 403/403/403 +f 404/404/404 412/412/412 414/414/414 +f 375/375/375 407/407/407 406/406/406 +f 404/404/404 407/407/407 412/412/412 +f 416/416/416 404/404/404 414/414/414 +f 418/418/418 419/419/419 420/420/420 +f 418/418/418 420/420/420 421/421/421 +f 420/420/420 422/422/422 423/423/423 +f 267/267/267 424/424/424 425/425/425 +f 268/268/268 426/426/426 424/424/424 +f 427/427/427 428/428/428 426/426/426 +f 424/424/424 429/429/429 425/425/425 +f 420/420/420 419/419/419 422/422/422 +f 263/263/263 421/421/421 423/423/423 +f 423/423/423 430/430/430 431/431/431 +f 430/430/430 394/394/394 275/275/275 +f 263/263/263 267/267/267 421/421/421 +f 431/431/431 275/275/275 270/270/270 +f 264/264/264 431/431/431 270/270/270 +f 263/263/263 431/431/431 264/264/264 +f 432/432/432 433/433/433 427/427/427 +f 434/434/434 432/432/432 427/427/427 +f 258/258/258 294/294/294 268/268/268 +f 368/368/368 434/434/434 285/285/285 +f 435/435/435 432/432/432 434/434/434 +f 286/286/286 294/294/294 287/287/287 +f 368/368/368 285/285/285 436/436/436 +f 286/286/286 434/434/434 427/427/427 +f 268/268/268 424/424/424 267/267/267 +f 267/267/267 425/425/425 418/418/418 +f 267/267/267 418/418/418 421/421/421 +f 426/426/426 268/268/268 294/294/294 +f 434/434/434 286/286/286 285/285/285 +f 294/294/294 286/286/286 426/426/426 +f 286/286/286 427/427/427 426/426/426 +f 431/431/431 430/430/430 275/275/275 +f 243/243/243 394/394/394 437/437/437 +f 239/239/239 238/238/238 438/438/438 +f 239/239/239 438/438/438 439/439/439 +f 437/437/437 238/238/238 243/243/243 +f 440/440/440 438/438/438 437/437/437 +f 441/441/441 442/442/442 440/440/440 +f 438/438/438 440/440/440 443/443/443 +f 239/239/239 439/439/439 296/296/296 +f 439/439/439 444/444/444 445/445/445 +f 439/439/439 446/446/446 444/444/444 +f 446/446/446 447/447/447 444/444/444 +f 296/296/296 439/439/439 445/445/445 +f 238/238/238 437/437/437 438/438/438 +f 439/439/439 438/438/438 443/443/443 +f 443/443/443 448/448/448 439/439/439 +f 430/430/430 449/449/449 450/450/450 +f 451/451/451 440/440/440 442/442/442 +f 442/442/442 450/450/450 451/451/451 +f 442/442/442 430/430/430 450/450/450 +f 263/263/263 423/423/423 431/431/431 +f 421/421/421 420/420/420 423/423/423 +f 449/449/449 430/430/430 423/423/423 +f 440/440/440 451/451/451 452/452/452 +f 453/453/453 430/430/430 442/442/442 +f 437/437/437 453/453/453 441/441/441 +f 441/441/441 440/440/440 437/437/437 +f 441/441/441 453/453/453 442/442/442 +f 452/452/452 443/443/443 440/440/440 +f 430/430/430 453/453/453 394/394/394 +f 453/453/453 437/437/437 394/394/394 +f 368/368/368 435/435/435 434/434/434 +f 312/312/312 317/317/317 454/454/454 +f 455/455/455 454/454/454 456/456/456 +f 317/317/317 312/312/312 311/311/311 +f 457/457/457 455/455/455 458/458/458 +f 317/317/317 459/459/459 460/460/460 +f 455/455/455 456/456/456 458/458/458 +f 461/461/461 458/458/458 456/456/456 +f 455/455/455 457/457/457 462/462/462 +f 365/365/365 355/355/355 463/463/463 +f 365/365/365 356/356/356 355/355/355 +f 315/315/315 314/314/314 343/343/343 +f 312/312/312 464/464/464 314/314/314 +f 464/464/464 455/455/455 462/462/462 +f 312/312/312 454/454/454 464/464/464 +f 464/464/464 454/454/454 455/455/455 +f 363/363/363 365/365/365 364/364/364 +f 362/362/362 364/364/364 347/347/347 +f 363/363/363 356/356/356 365/365/365 +f 465/465/465 362/362/362 347/347/347 +f 466/466/466 467/467/467 468/468/468 +f 469/469/469 316/316/316 470/470/470 +f 347/347/347 346/346/346 465/465/465 +f 471/471/471 360/360/360 361/361/361 +f 311/311/311 470/470/470 316/316/316 +f 459/459/459 316/316/316 469/469/469 +f 317/317/317 316/316/316 459/459/459 +f 311/311/311 471/471/471 470/470/470 +f 363/363/363 361/361/361 356/356/356 +f 471/471/471 361/361/361 363/363/363 +f 311/311/311 360/360/360 471/471/471 +f 366/366/366 365/365/365 463/463/463 +f 472/472/472 473/473/473 474/474/474 +f 474/474/474 338/338/338 472/472/472 +f 370/370/370 475/475/475 367/367/367 +f 370/370/370 349/349/349 475/475/475 +f 338/338/338 474/474/474 476/476/476 +f 367/367/367 475/475/475 477/477/477 +f 349/349/349 473/473/473 475/475/475 +f 478/478/478 367/367/367 477/477/477 +f 432/432/432 435/435/435 479/479/479 +f 480/480/480 433/433/433 432/432/432 +f 368/368/368 478/478/478 435/435/435 +f 435/435/435 481/481/481 479/479/479 +f 475/475/475 473/473/473 477/477/477 +f 368/368/368 367/367/367 478/478/478 +f 478/478/478 481/481/481 435/435/435 +f 463/463/463 355/355/355 339/339/339 +f 370/370/370 371/371/371 482/482/482 +f 370/370/370 346/346/346 345/345/345 +f 338/338/338 463/463/463 339/339/339 +f 348/348/348 347/347/347 366/366/366 +f 338/338/338 476/476/476 463/463/463 +f 476/476/476 366/366/366 463/463/463 +f 370/370/370 482/482/482 346/346/346 +f 349/349/349 483/483/483 473/473/473 +f 366/366/366 483/483/483 349/349/349 +f 366/366/366 476/476/476 474/474/474 +f 366/366/366 474/474/474 483/483/483 +f 483/483/483 474/474/474 473/473/473 +f 345/345/345 349/349/349 370/370/370 +f 348/348/348 366/366/366 349/349/349 +f 239/239/239 296/296/296 242/242/242 +f 484/484/484 485/485/485 486/486/486 +f 485/485/485 487/487/487 488/488/488 +f 485/485/485 489/489/489 486/486/486 +f 485/485/485 484/484/484 487/487/487 +f 487/487/487 484/484/484 212/212/212 +f 487/487/487 490/490/490 488/488/488 +f 491/491/491 490/490/490 487/487/487 +f 207/207/207 484/484/484 217/217/217 +f 486/486/486 489/489/489 492/492/492 +f 486/486/486 492/492/492 493/493/493 +f 494/494/494 486/486/486 493/493/493 +f 486/486/486 494/494/494 495/495/495 +f 484/484/484 495/495/495 217/217/217 +f 207/207/207 212/212/212 484/484/484 +f 495/495/495 484/484/484 486/486/486 +f 496/496/496 497/497/497 498/498/498 +f 498/498/498 499/499/499 500/500/500 +f 498/498/498 497/497/497 499/499/499 +f 498/498/498 501/501/501 496/496/496 +f 502/502/502 503/503/503 504/504/504 +f 496/496/496 501/501/501 505/505/505 +f 501/501/501 504/504/504 505/505/505 +f 506/506/506 507/507/507 490/490/490 +f 506/506/506 498/498/498 507/507/507 +f 508/508/508 509/509/509 510/510/510 +f 491/491/491 487/487/487 212/212/212 +f 508/508/508 510/510/510 507/507/507 +f 491/491/491 506/506/506 490/490/490 +f 507/507/507 510/510/510 490/490/490 +f 510/510/510 488/488/488 490/490/490 +f 492/492/492 511/511/511 493/493/493 +f 279/279/279 512/512/512 276/276/276 +f 276/276/276 513/513/513 277/277/277 +f 277/277/277 281/281/281 278/278/278 +f 512/512/512 252/252/252 514/514/514 +f 252/252/252 512/512/512 253/253/253 +f 229/229/229 213/213/213 208/208/208 +f 276/276/276 512/512/512 514/514/514 +f 515/515/515 513/513/513 276/276/276 +f 513/513/513 516/516/516 280/280/280 +f 256/256/256 283/283/283 254/254/254 +f 279/279/279 283/283/283 256/256/256 +f 277/277/277 513/513/513 280/280/280 +f 276/276/276 514/514/514 515/515/515 +f 516/516/516 515/515/515 517/517/517 +f 516/516/516 513/513/513 515/515/515 +f 252/252/252 251/251/251 514/514/514 +f 251/251/251 518/518/518 514/514/514 +f 518/518/518 519/519/519 515/515/515 +f 495/495/495 494/494/494 518/518/518 +f 229/229/229 253/253/253 249/249/249 +f 495/495/495 251/251/251 217/217/217 +f 518/518/518 251/251/251 495/495/495 +f 515/515/515 514/514/514 518/518/518 +f 515/515/515 519/519/519 517/517/517 +f 519/519/519 520/520/520 517/517/517 +f 253/253/253 512/512/512 279/279/279 +f 493/493/493 511/511/511 520/520/520 +f 493/493/493 519/519/519 494/494/494 +f 519/519/519 518/518/518 494/494/494 +f 520/520/520 519/519/519 493/493/493 +f 504/504/504 501/501/501 502/502/502 +f 445/445/445 521/521/521 522/522/522 +f 522/522/522 296/296/296 445/445/445 +f 523/523/523 521/521/521 444/444/444 +f 524/524/524 525/525/525 526/526/526 +f 525/525/525 524/524/524 527/527/527 +f 527/527/527 528/528/528 525/525/525 +f 529/529/529 524/524/524 526/526/526 +f 521/521/521 445/445/445 444/444/444 +f 530/530/530 531/531/531 496/496/496 +f 496/496/496 505/505/505 530/530/530 +f 529/529/529 531/531/531 532/532/532 +f 521/521/521 530/530/530 505/505/505 +f 530/530/530 521/521/521 523/523/523 +f 523/523/523 532/532/532 530/530/530 +f 522/522/522 521/521/521 505/505/505 +f 523/523/523 444/444/444 447/447/447 +f 533/533/533 534/534/534 535/535/535 +f 534/534/534 447/447/447 535/535/535 +f 447/447/447 534/534/534 523/523/523 +f 446/446/446 439/439/439 448/448/448 +f 447/447/447 446/446/446 448/448/448 +f 448/448/448 535/535/535 447/447/447 +f 536/536/536 534/534/534 533/533/533 +f 529/529/529 532/532/532 536/536/536 +f 527/527/527 536/536/536 537/537/537 +f 527/527/527 524/524/524 536/536/536 +f 536/536/536 524/524/524 529/529/529 +f 533/533/533 537/537/537 536/536/536 +f 523/523/523 534/534/534 532/532/532 +f 534/534/534 536/536/536 532/532/532 +f 531/531/531 530/530/530 532/532/532 +f 522/522/522 505/505/505 504/504/504 +f 203/203/203 538/538/538 491/491/491 +f 212/212/212 203/203/203 491/491/491 +f 504/504/504 539/539/539 522/522/522 +f 540/540/540 292/292/292 295/295/295 +f 522/522/522 539/539/539 296/296/296 +f 539/539/539 295/295/295 296/296/296 +f 538/538/538 203/203/203 541/541/541 +f 502/502/502 506/506/506 491/491/491 +f 502/502/502 501/501/501 506/506/506 +f 501/501/501 498/498/498 506/506/506 +f 491/491/491 538/538/538 502/502/502 +f 203/203/203 205/205/205 541/541/541 +f 502/502/502 538/538/538 503/503/503 +f 538/538/538 541/541/541 503/503/503 +f 209/209/209 542/542/542 205/205/205 +f 542/542/542 541/541/541 205/205/205 +f 289/289/289 542/542/542 209/209/209 +f 531/531/531 543/543/543 497/497/497 +f 543/543/543 531/531/531 529/529/529 +f 529/529/529 526/526/526 543/543/543 +f 496/496/496 531/531/531 497/497/497 +f 209/209/209 228/228/228 289/289/289 +f 540/540/540 539/539/539 503/503/503 +f 539/539/539 504/504/504 503/503/503 +f 295/295/295 539/539/539 540/540/540 +f 540/540/540 503/503/503 541/541/541 +f 540/540/540 542/542/542 292/292/292 +f 542/542/542 289/289/289 292/292/292 +f 541/541/541 542/542/542 540/540/540 +f 351/351/351 350/350/350 544/544/544 +f 545/545/545 546/546/546 547/547/547 +f 548/548/548 545/545/545 547/547/547 +f 548/548/548 549/549/549 545/545/545 +f 547/547/547 546/546/546 550/550/550 +f 551/551/551 552/552/552 553/553/553 +f 553/553/553 552/552/552 554/554/554 +f 551/551/551 555/555/555 552/552/552 +f 556/556/556 549/549/549 548/548/548 +f 557/557/557 389/389/389 558/558/558 +f 389/389/389 388/388/388 558/558/558 +f 399/399/399 389/389/389 557/557/557 +f 388/388/388 390/390/390 558/558/558 +f 556/556/556 390/390/390 549/549/549 +f 559/559/559 390/390/390 556/556/556 +f 558/558/558 390/390/390 559/559/559 +f 425/425/425 560/560/560 418/418/418 +f 561/561/561 560/560/560 429/429/429 +f 560/560/560 425/425/425 429/429/429 +f 560/560/560 562/562/562 419/419/419 +f 563/563/563 553/553/553 564/564/564 +f 551/551/551 553/553/553 565/565/565 +f 553/553/553 563/563/563 565/565/565 +f 562/562/562 560/560/560 561/561/561 +f 566/566/566 422/422/422 555/555/555 +f 555/555/555 551/551/551 566/566/566 +f 546/546/546 563/563/563 564/564/564 +f 555/555/555 422/422/422 562/562/562 +f 561/561/561 555/555/555 562/562/562 +f 562/562/562 422/422/422 419/419/419 +f 418/418/418 560/560/560 419/419/419 +f 567/567/567 399/399/399 557/557/557 +f 568/568/568 569/569/569 570/570/570 +f 571/571/571 570/570/570 572/572/572 +f 569/569/569 573/573/573 574/574/574 +f 568/568/568 575/575/575 569/569/569 +f 576/576/576 577/577/577 578/578/578 +f 579/579/579 580/580/580 581/581/581 +f 575/575/575 573/573/573 569/569/569 +f 569/569/569 582/582/582 572/572/572 +f 570/570/570 571/571/571 583/583/583 +f 583/583/583 568/568/568 570/570/570 +f 584/584/584 571/571/571 572/572/572 +f 571/571/571 584/584/584 585/585/585 +f 569/569/569 574/574/574 582/582/582 +f 570/570/570 569/569/569 572/572/572 +f 583/583/583 571/571/571 585/585/585 +f 576/576/576 586/586/586 587/587/587 +f 580/580/580 576/576/576 578/578/578 +f 587/587/587 588/588/588 576/576/576 +f 587/587/587 586/586/586 589/589/589 +f 398/398/398 399/399/399 567/567/567 +f 590/590/590 398/398/398 567/567/567 +f 247/247/247 398/398/398 590/590/590 +f 588/588/588 591/591/591 592/592/592 +f 572/572/572 582/582/582 580/580/580 +f 586/586/586 576/576/576 580/580/580 +f 580/580/580 578/578/578 581/581/581 +f 574/574/574 586/586/586 580/580/580 +f 576/576/576 588/588/588 577/577/577 +f 588/588/588 592/592/592 577/577/577 +f 582/582/582 574/574/574 580/580/580 +f 593/593/593 550/550/550 594/594/594 +f 567/567/567 557/557/557 595/595/595 +f 557/557/557 596/596/596 595/595/595 +f 597/597/597 598/598/598 596/596/596 +f 590/590/590 567/567/567 595/595/595 +f 599/599/599 600/600/600 601/601/601 +f 602/602/602 601/601/601 603/603/603 +f 602/602/602 603/603/603 604/604/604 +f 598/598/598 595/595/595 596/596/596 +f 605/605/605 557/557/557 558/558/558 +f 605/605/605 606/606/606 597/597/597 +f 597/597/597 596/596/596 605/605/605 +f 607/607/607 606/606/606 605/605/605 +f 608/608/608 609/609/609 610/610/610 +f 607/607/607 611/611/611 612/612/612 +f 607/607/607 612/612/612 606/606/606 +f 613/613/613 614/614/614 615/615/615 +f 616/616/616 218/218/218 617/617/617 +f 615/615/615 616/616/616 617/617/617 +f 613/613/613 615/615/615 618/618/618 +f 613/613/613 619/619/619 620/620/620 +f 619/619/619 613/613/613 618/618/618 +f 621/621/621 622/622/622 618/618/618 +f 623/623/623 624/624/624 625/625/625 +f 599/599/599 626/626/626 600/600/600 +f 626/626/626 627/627/627 600/600/600 +f 624/624/624 627/627/627 626/626/626 +f 628/628/628 615/615/615 617/617/617 +f 624/624/624 621/621/621 618/618/618 +f 629/629/629 618/618/618 615/615/615 +f 628/628/628 629/629/629 615/615/615 +f 607/607/607 558/558/558 559/559/559 +f 555/555/555 561/561/561 552/552/552 +f 630/630/630 631/631/631 632/632/632 +f 632/632/632 631/631/631 633/633/633 +f 561/561/561 632/632/632 552/552/552 +f 610/610/610 607/607/607 608/608/608 +f 561/561/561 630/630/630 632/632/632 +f 561/561/561 429/429/429 630/630/630 +f 633/633/633 594/594/594 554/554/554 +f 564/564/564 550/550/550 546/546/546 +f 554/554/554 550/550/550 564/564/564 +f 564/564/564 553/553/553 554/554/554 +f 633/633/633 593/593/593 594/594/594 +f 550/550/550 554/554/554 594/594/594 +f 552/552/552 632/632/632 554/554/554 +f 632/632/632 633/633/633 554/554/554 +f 593/593/593 633/633/633 634/634/634 +f 634/634/634 609/609/609 608/608/608 +f 593/593/593 634/634/634 608/608/608 +f 634/634/634 633/633/633 635/635/635 +f 607/607/607 559/559/559 608/608/608 +f 607/607/607 605/605/605 558/558/558 +f 557/557/557 605/605/605 596/596/596 +f 593/593/593 608/608/608 636/636/636 +f 608/608/608 559/559/559 556/556/556 +f 548/548/548 608/608/608 556/556/556 +f 610/610/610 611/611/611 607/607/607 +f 636/636/636 548/548/548 547/547/547 +f 593/593/593 547/547/547 550/550/550 +f 548/548/548 636/636/636 608/608/608 +f 593/593/593 636/636/636 547/547/547 +f 572/572/572 579/579/579 584/584/584 +f 637/637/637 638/638/638 639/639/639 +f 640/640/640 639/639/639 638/638/638 +f 637/637/637 641/641/641 638/638/638 +f 642/642/642 643/643/643 644/644/644 +f 645/645/645 646/646/646 647/647/647 +f 648/648/648 649/649/649 650/650/650 +f 642/642/642 644/644/644 651/651/651 +f 417/417/417 638/638/638 641/641/641 +f 652/652/652 653/653/653 654/654/654 +f 655/655/655 654/654/654 653/653/653 +f 652/652/652 656/656/656 657/657/657 +f 653/653/653 637/637/637 655/655/655 +f 637/637/637 653/653/653 641/641/641 +f 657/657/657 641/641/641 653/653/653 +f 637/637/637 639/639/639 655/655/655 +f 658/658/658 659/659/659 660/660/660 +f 661/661/661 662/662/662 663/663/663 +f 664/664/664 663/663/663 662/662/662 +f 659/659/659 665/665/665 660/660/660 +f 586/586/586 574/574/574 666/666/666 +f 667/667/667 668/668/668 661/661/661 +f 668/668/668 662/662/662 661/661/661 +f 669/669/669 670/670/670 664/664/664 +f 648/648/648 650/650/650 671/671/671 +f 671/671/671 672/672/672 673/673/673 +f 672/672/672 674/674/674 673/673/673 +f 673/673/673 648/648/648 671/671/671 +f 662/662/662 669/669/669 664/664/664 +f 675/675/675 660/660/660 676/676/676 +f 677/677/677 660/660/660 675/675/675 +f 653/653/653 652/652/652 657/657/657 +f 678/678/678 679/679/679 680/680/680 +f 679/679/679 681/681/681 682/682/682 +f 681/681/681 679/679/679 683/683/683 +f 679/679/679 682/682/682 680/680/680 +f 684/684/684 685/685/685 686/686/686 +f 683/683/683 687/687/687 686/686/686 +f 688/688/688 687/687/687 683/683/683 +f 683/683/683 679/679/679 688/688/688 +f 689/689/689 690/690/690 691/691/691 +f 689/689/689 692/692/692 690/690/690 +f 693/693/693 690/690/690 692/692/692 +f 694/694/694 695/695/695 696/696/696 +f 679/679/679 678/678/678 695/695/695 +f 688/688/688 679/679/679 695/695/695 +f 695/695/695 678/678/678 696/696/696 +f 697/697/697 639/639/639 698/698/698 +f 640/640/640 699/699/699 639/639/639 +f 639/639/639 697/697/697 684/684/684 +f 639/639/639 699/699/699 698/698/698 +f 652/652/652 700/700/700 656/656/656 +f 329/329/329 656/656/656 700/700/700 +f 700/700/700 652/652/652 701/701/701 +f 655/655/655 639/639/639 684/684/684 +f 698/698/698 702/702/702 697/697/697 +f 681/681/681 683/683/683 686/686/686 +f 685/685/685 681/681/681 686/686/686 +f 697/697/697 702/702/702 684/684/684 +f 684/684/684 686/686/686 655/655/655 +f 654/654/654 655/655/655 687/687/687 +f 655/655/655 686/686/686 687/687/687 +f 574/574/574 573/573/573 666/666/666 +f 703/703/703 578/578/578 577/577/577 +f 704/704/704 703/703/703 705/705/705 +f 705/705/705 591/591/591 706/706/706 +f 707/707/707 581/581/581 578/578/578 +f 704/704/704 708/708/708 703/703/703 +f 709/709/709 707/707/707 703/703/703 +f 578/578/578 703/703/703 707/707/707 +f 706/706/706 704/704/704 705/705/705 +f 710/710/710 591/591/591 711/711/711 +f 710/710/710 711/711/711 712/712/712 +f 713/713/713 708/708/708 704/704/704 +f 710/710/710 706/706/706 591/591/591 +f 592/592/592 705/705/705 577/577/577 +f 705/705/705 703/703/703 577/577/577 +f 591/591/591 705/705/705 592/592/592 +f 714/714/714 715/715/715 716/716/716 +f 717/717/717 718/718/718 585/585/585 +f 715/715/715 719/719/719 579/579/579 +f 714/714/714 717/717/717 715/715/715 +f 572/572/572 580/580/580 579/579/579 +f 720/720/720 717/717/717 714/714/714 +f 717/717/717 719/719/719 715/715/715 +f 719/719/719 584/584/584 579/579/579 +f 579/579/579 707/707/707 715/715/715 +f 707/707/707 579/579/579 581/581/581 +f 721/721/721 709/709/709 708/708/708 +f 714/714/714 716/716/716 709/709/709 +f 709/709/709 716/716/716 707/707/707 +f 708/708/708 709/709/709 703/703/703 +f 715/715/715 707/707/707 716/716/716 +f 713/713/713 704/704/704 706/706/706 +f 722/722/722 723/723/723 718/718/718 +f 723/723/723 722/722/722 724/724/724 +f 725/725/725 726/726/726 713/713/713 +f 727/727/727 585/585/585 723/723/723 +f 584/584/584 719/719/719 585/585/585 +f 585/585/585 718/718/718 723/723/723 +f 719/719/719 717/717/717 585/585/585 +f 709/709/709 721/721/721 728/728/728 +f 727/727/727 724/724/724 729/729/729 +f 583/583/583 727/727/727 729/729/729 +f 568/568/568 729/729/729 575/575/575 +f 568/568/568 583/583/583 729/729/729 +f 709/709/709 728/728/728 714/714/714 +f 583/583/583 585/585/585 727/727/727 +f 727/727/727 723/723/723 724/724/724 +f 721/721/721 708/708/708 726/726/726 +f 721/721/721 726/726/726 728/728/728 +f 728/728/728 726/726/726 725/725/725 +f 710/710/710 730/730/730 731/731/731 +f 710/710/710 731/731/731 725/725/725 +f 710/710/710 725/725/725 713/713/713 +f 708/708/708 713/713/713 726/726/726 +f 710/710/710 713/713/713 706/706/706 +f 717/717/717 720/720/720 718/718/718 +f 722/722/722 720/720/720 728/728/728 +f 728/728/728 720/720/720 714/714/714 +f 722/722/722 718/718/718 720/720/720 +f 730/730/730 710/710/710 712/712/712 +f 246/246/246 731/731/731 730/730/730 +f 712/712/712 246/246/246 730/730/730 +f 464/464/464 462/462/462 732/732/732 +f 464/464/464 732/732/732 341/341/341 +f 314/314/314 464/464/464 341/341/341 +f 733/733/733 479/479/479 734/734/734 +f 735/735/735 736/736/736 737/737/737 +f 734/734/734 738/738/738 733/733/733 +f 738/738/738 739/739/739 733/733/733 +f 343/343/343 314/314/314 341/341/341 +f 740/740/740 741/741/741 739/739/739 +f 741/741/741 742/742/742 743/743/743 +f 742/742/742 744/744/744 743/743/743 +f 359/359/359 358/358/358 355/355/355 +f 339/339/339 358/358/358 336/336/336 +f 315/315/315 339/339/339 336/336/336 +f 339/339/339 355/355/355 358/358/358 +f 745/745/745 746/746/746 747/747/747 +f 747/747/747 748/748/748 745/745/745 +f 749/749/749 745/745/745 748/748/748 +f 746/746/746 750/750/750 747/747/747 +f 751/751/751 752/752/752 750/750/750 +f 753/753/753 751/751/751 750/750/750 +f 746/746/746 753/753/753 750/750/750 +f 754/754/754 749/749/749 755/755/755 +f 756/756/756 757/757/757 736/736/736 +f 736/736/736 758/758/758 756/756/756 +f 757/757/757 737/737/737 736/736/736 +f 350/350/350 756/756/756 758/758/758 +f 749/749/749 748/748/748 755/755/755 +f 755/755/755 735/735/735 754/754/754 +f 737/737/737 754/754/754 735/735/735 +f 744/744/744 742/742/742 462/462/462 +f 759/759/759 760/760/760 761/761/761 +f 759/759/759 761/761/761 762/762/762 +f 465/465/465 761/761/761 763/763/763 +f 761/761/761 760/760/760 763/763/763 +f 764/764/764 763/763/763 760/760/760 +f 765/765/765 766/766/766 767/767/767 +f 766/766/766 764/764/764 759/759/759 +f 764/764/764 760/760/760 759/759/759 +f 482/482/482 768/768/768 762/762/762 +f 762/762/762 346/346/346 482/482/482 +f 769/769/769 770/770/770 768/768/768 +f 762/762/762 768/768/768 771/771/771 +f 767/767/767 759/759/759 762/762/762 +f 762/762/762 761/761/761 346/346/346 +f 767/767/767 762/762/762 771/771/771 +f 473/473/473 472/472/472 772/772/772 +f 772/772/772 477/477/477 473/473/473 +f 772/772/772 773/773/773 477/477/477 +f 477/477/477 481/481/481 478/478/478 +f 742/742/742 774/774/774 462/462/462 +f 742/742/742 741/741/741 774/774/774 +f 741/741/741 740/740/740 774/774/774 +f 773/773/773 772/772/772 775/775/775 +f 769/769/769 768/768/768 371/371/371 +f 768/768/768 482/482/482 371/371/371 +f 436/436/436 369/369/369 368/368/368 +f 465/465/465 346/346/346 761/761/761 +f 472/472/472 775/775/775 772/772/772 +f 775/775/775 472/472/472 776/776/776 +f 338/338/338 340/340/340 472/472/472 +f 752/752/752 777/777/777 750/750/750 +f 778/778/778 751/751/751 479/479/479 +f 751/751/751 753/753/753 479/479/479 +f 778/778/778 479/479/479 481/481/481 +f 778/778/778 481/481/481 477/477/477 +f 779/779/779 752/752/752 751/751/751 +f 751/751/751 778/778/778 779/779/779 +f 477/477/477 779/779/779 778/778/778 +f 753/753/753 746/746/746 479/479/479 +f 780/780/780 745/745/745 781/781/781 +f 745/745/745 749/749/749 781/781/781 +f 780/780/780 781/781/781 738/738/738 +f 734/734/734 780/780/780 738/738/738 +f 479/479/479 746/746/746 780/780/780 +f 479/479/479 780/780/780 734/734/734 +f 746/746/746 745/745/745 780/780/780 +f 776/776/776 782/782/782 783/783/783 +f 340/340/340 783/783/783 782/782/782 +f 782/782/782 472/472/472 340/340/340 +f 783/783/783 544/544/544 776/776/776 +f 544/544/544 783/783/783 351/351/351 +f 337/337/337 351/351/351 783/783/783 +f 783/783/783 340/340/340 337/337/337 +f 472/472/472 782/782/782 776/776/776 +f 752/752/752 779/779/779 784/784/784 +f 773/773/773 784/784/784 779/779/779 +f 779/779/779 477/477/477 773/773/773 +f 784/784/784 777/777/777 752/752/752 +f 784/784/784 775/775/775 776/776/776 +f 784/784/784 776/776/776 777/777/777 +f 784/784/784 773/773/773 775/775/775 +f 749/749/749 754/754/754 781/781/781 +f 785/785/785 352/352/352 342/342/342 +f 785/785/785 350/350/350 352/352/352 +f 354/354/354 342/342/342 352/352/352 +f 342/342/342 341/341/341 785/785/785 +f 786/786/786 787/787/787 737/737/737 +f 787/787/787 786/786/786 732/732/732 +f 732/732/732 462/462/462 787/787/787 +f 353/353/353 354/354/354 352/352/352 +f 788/788/788 789/789/789 776/776/776 +f 777/777/777 776/776/776 789/789/789 +f 789/789/789 750/750/750 777/777/777 +f 776/776/776 544/544/544 788/788/788 +f 344/344/344 353/353/353 352/352/352 +f 544/544/544 350/350/350 758/758/758 +f 758/758/758 788/788/788 544/544/544 +f 740/740/740 790/790/790 774/774/774 +f 790/790/790 754/754/754 774/774/774 +f 754/754/754 737/737/737 787/787/787 +f 781/781/781 790/790/790 740/740/740 +f 738/738/738 781/781/781 739/739/739 +f 781/781/781 754/754/754 790/790/790 +f 739/739/739 781/781/781 740/740/740 +f 774/774/774 754/754/754 462/462/462 +f 341/341/341 732/732/732 785/785/785 +f 786/786/786 785/785/785 732/732/732 +f 737/737/737 757/757/757 786/786/786 +f 785/785/785 786/786/786 757/757/757 +f 754/754/754 787/787/787 462/462/462 +f 756/756/756 350/350/350 785/785/785 +f 757/757/757 756/756/756 785/785/785 +f 791/791/791 792/792/792 793/793/793 +f 794/794/794 795/795/795 621/621/621 +f 627/627/627 604/604/604 603/603/603 +f 624/624/624 604/604/604 627/627/627 +f 626/626/626 599/599/599 794/794/794 +f 794/794/794 599/599/599 796/796/796 +f 794/794/794 621/621/621 624/624/624 +f 626/626/626 794/794/794 624/624/624 +f 797/797/797 791/791/791 604/604/604 +f 602/602/602 798/798/798 799/799/799 +f 799/799/799 798/798/798 791/791/791 +f 800/800/800 801/801/801 802/802/802 +f 799/799/799 802/802/802 801/801/801 +f 798/798/798 602/602/602 604/604/604 +f 791/791/791 798/798/798 604/604/604 +f 602/602/602 799/799/799 801/801/801 +f 803/803/803 804/804/804 805/805/805 +f 804/804/804 806/806/806 807/807/807 +f 795/795/795 796/796/796 807/807/807 +f 796/796/796 805/805/805 804/804/804 +f 808/808/808 803/803/803 809/809/809 +f 803/803/803 793/793/793 804/804/804 +f 803/803/803 805/805/805 809/809/809 +f 807/807/807 810/810/810 811/811/811 +f 795/795/795 807/807/807 622/622/622 +f 795/795/795 622/622/622 621/621/621 +f 794/794/794 796/796/796 795/795/795 +f 622/622/622 619/619/619 618/618/618 +f 796/796/796 804/804/804 807/807/807 +f 622/622/622 807/807/807 619/619/619 +f 807/807/807 811/811/811 619/619/619 +f 812/812/812 800/800/800 802/802/802 +f 813/813/813 814/814/814 815/815/815 +f 814/814/814 816/816/816 287/287/287 +f 290/290/290 815/815/815 287/287/287 +f 814/814/814 810/810/810 806/806/806 +f 807/807/807 806/806/806 810/810/810 +f 811/811/811 810/810/810 813/813/813 +f 814/814/814 806/806/806 817/817/817 +f 810/810/810 814/814/814 813/813/813 +f 620/620/620 614/614/614 613/613/613 +f 620/620/620 619/619/619 811/811/811 +f 811/811/811 813/813/813 620/620/620 +f 614/614/614 616/616/616 615/615/615 +f 813/813/813 225/225/225 620/620/620 +f 616/616/616 614/614/614 293/293/293 +f 293/293/293 218/218/218 616/616/616 +f 601/601/601 602/602/602 801/801/801 +f 800/800/800 601/601/601 801/801/801 +f 809/809/809 805/805/805 818/818/818 +f 800/800/800 818/818/818 601/601/601 +f 799/799/799 808/808/808 802/802/802 +f 818/818/818 800/800/800 812/812/812 +f 812/812/812 809/809/809 818/818/818 +f 796/796/796 818/818/818 805/805/805 +f 819/819/819 369/369/369 436/436/436 +f 769/769/769 371/371/371 369/369/369 +f 817/817/817 819/819/819 436/436/436 +f 600/600/600 627/627/627 603/603/603 +f 601/601/601 818/818/818 796/796/796 +f 796/796/796 599/599/599 601/601/601 +f 603/603/603 601/601/601 600/600/600 +f 808/808/808 793/793/793 803/803/803 +f 225/225/225 614/614/614 620/620/620 +f 813/813/813 290/290/290 225/225/225 +f 225/225/225 293/293/293 614/614/614 +f 290/290/290 813/813/813 815/815/815 +f 816/816/816 820/820/820 285/285/285 +f 815/815/815 814/814/814 287/287/287 +f 816/816/816 285/285/285 287/287/287 +f 617/617/617 232/232/232 231/231/231 +f 821/821/821 244/244/244 245/245/245 +f 618/618/618 629/629/629 822/822/822 +f 822/822/822 625/625/625 618/618/618 +f 628/628/628 231/231/231 821/821/821 +f 617/617/617 218/218/218 232/232/232 +f 628/628/628 617/617/617 231/231/231 +f 231/231/231 244/244/244 821/821/821 +f 823/823/823 770/770/770 824/824/824 +f 369/369/369 824/824/824 769/769/769 +f 819/819/819 824/824/824 369/369/369 +f 770/770/770 769/769/769 824/824/824 +f 791/791/791 823/823/823 792/792/792 +f 823/823/823 824/824/824 819/819/819 +f 792/792/792 823/823/823 819/819/819 +f 820/820/820 814/814/814 817/817/817 +f 804/804/804 817/817/817 806/806/806 +f 820/820/820 816/816/816 814/814/814 +f 820/820/820 436/436/436 285/285/285 +f 817/817/817 436/436/436 820/820/820 +f 793/793/793 792/792/792 817/817/817 +f 793/793/793 817/817/817 804/804/804 +f 792/792/792 819/819/819 817/817/817 +f 825/825/825 629/629/629 628/628/628 +f 771/771/771 770/770/770 826/826/826 +f 771/771/771 768/768/768 770/770/770 +f 826/826/826 827/827/827 767/767/767 +f 791/791/791 797/797/797 623/623/623 +f 822/822/822 767/767/767 625/625/625 +f 767/767/767 827/827/827 623/623/623 +f 791/791/791 623/623/623 827/827/827 +f 826/826/826 767/767/767 771/771/771 +f 791/791/791 826/826/826 770/770/770 +f 808/808/808 812/812/812 802/802/802 +f 809/809/809 812/812/812 808/808/808 +f 791/791/791 793/793/793 808/808/808 +f 791/791/791 827/827/827 826/826/826 +f 791/791/791 770/770/770 823/823/823 +f 808/808/808 799/799/799 791/791/791 +f 828/828/828 765/765/765 825/825/825 +f 825/825/825 829/829/829 828/828/828 +f 822/822/822 765/765/765 767/767/767 +f 825/825/825 765/765/765 822/822/822 +f 628/628/628 821/821/821 825/825/825 +f 829/829/829 825/825/825 821/821/821 +f 821/821/821 245/245/245 829/829/829 +f 765/765/765 828/828/828 766/766/766 +f 624/624/624 618/618/618 625/625/625 +f 797/797/797 604/604/604 623/623/623 +f 767/767/767 623/623/623 625/625/625 +f 623/623/623 604/604/604 624/624/624 +f 764/764/764 766/766/766 828/828/828 +f 629/629/629 825/825/825 822/822/822 +f 766/766/766 759/759/759 767/767/767 +f 830/830/830 831/831/831 832/832/832 +f 833/833/833 834/834/834 835/835/835 +f 836/836/836 835/835/835 837/837/837 +f 833/833/833 835/835/835 836/836/836 +f 838/838/838 833/833/833 839/839/839 +f 838/838/838 840/840/840 833/833/833 +f 832/832/832 833/833/833 840/840/840 +f 837/837/837 841/841/841 842/842/842 +f 841/841/841 843/843/843 842/842/842 +f 836/836/836 837/837/837 844/844/844 +f 843/843/843 845/845/845 846/846/846 +f 842/842/842 847/847/847 844/844/844 +f 848/848/848 841/841/841 837/837/837 +f 837/837/837 842/842/842 844/844/844 +f 839/839/839 836/836/836 844/844/844 +f 849/849/849 850/850/850 851/851/851 +f 852/852/852 853/853/853 854/854/854 +f 855/855/855 852/852/852 854/854/854 +f 854/854/854 853/853/853 856/856/856 +f 857/857/857 850/850/850 849/849/849 +f 856/856/856 853/853/853 858/858/858 +f 849/849/849 856/856/856 858/858/858 +f 858/858/858 853/853/853 852/852/852 +f 859/859/859 830/830/830 858/858/858 +f 852/852/852 859/859/859 858/858/858 +f 833/833/833 836/836/836 839/839/839 +f 849/849/849 858/858/858 830/830/830 +f 832/832/832 860/860/860 830/830/830 +f 849/849/849 830/830/830 860/860/860 +f 849/849/849 860/860/860 861/861/861 +f 862/862/862 863/863/863 864/864/864 +f 865/865/865 846/846/846 866/866/866 +f 867/867/867 868/868/868 869/869/869 +f 870/870/870 871/871/871 872/872/872 +f 873/873/873 874/874/874 865/865/865 +f 875/875/875 874/874/874 876/876/876 +f 871/871/871 877/877/877 876/876/876 +f 862/862/862 878/878/878 875/875/875 +f 872/872/872 879/879/879 870/870/870 +f 880/880/880 881/881/881 882/882/882 +f 879/879/879 872/872/872 883/883/883 +f 883/883/883 884/884/884 879/879/879 +f 869/869/869 882/882/882 873/873/873 +f 871/871/871 870/870/870 885/885/885 +f 876/876/876 881/881/881 871/871/871 +f 881/881/881 876/876/876 882/882/882 +f 878/878/878 865/865/865 874/874/874 +f 878/878/878 874/874/874 875/875/875 +f 865/865/865 878/878/878 847/847/847 +f 844/844/844 847/847/847 878/878/878 +f 862/862/862 864/864/864 844/844/844 +f 864/864/864 839/839/839 844/844/844 +f 862/862/862 844/844/844 878/878/878 +f 847/847/847 842/842/842 865/865/865 +f 877/877/877 886/886/886 863/863/863 +f 875/875/875 877/877/877 862/862/862 +f 877/877/877 875/875/875 876/876/876 +f 862/862/862 877/877/877 863/863/863 +f 873/873/873 865/865/865 866/866/866 +f 886/886/886 877/877/877 871/871/871 +f 871/871/871 885/885/885 886/886/886 +f 851/851/851 887/887/887 854/854/854 +f 888/888/888 889/889/889 890/890/890 +f 891/891/891 892/892/892 893/893/893 +f 894/894/894 892/892/892 891/891/891 +f 888/888/888 893/893/893 889/889/889 +f 845/845/845 843/843/843 895/895/895 +f 896/896/896 841/841/841 897/897/897 +f 892/892/892 894/894/894 889/889/889 +f 891/891/891 898/898/898 899/899/899 +f 900/900/900 901/901/901 902/902/902 +f 901/901/901 903/903/903 902/902/902 +f 894/894/894 901/901/901 900/900/900 +f 891/891/891 896/896/896 898/898/898 +f 894/894/894 891/891/891 899/899/899 +f 893/893/893 895/895/895 891/891/891 +f 896/896/896 904/904/904 898/898/898 +f 841/841/841 848/848/848 897/897/897 +f 905/905/905 906/906/906 907/907/907 +f 907/907/907 906/906/906 908/908/908 +f 909/909/909 910/910/910 848/848/848 +f 911/911/911 908/908/908 912/912/912 +f 908/908/908 848/848/848 912/912/912 +f 913/913/913 907/907/907 908/908/908 +f 848/848/848 914/914/914 897/897/897 +f 893/893/893 888/888/888 845/845/845 +f 893/893/893 845/845/845 895/895/895 +f 895/895/895 896/896/896 891/891/891 +f 893/893/893 892/892/892 889/889/889 +f 915/915/915 904/904/904 914/914/914 +f 896/896/896 895/895/895 841/841/841 +f 843/843/843 841/841/841 895/895/895 +f 900/900/900 889/889/889 894/894/894 +f 916/916/916 917/917/917 918/918/918 +f 916/916/916 918/918/918 919/919/919 +f 920/920/920 887/887/887 851/851/851 +f 918/918/918 851/851/851 850/850/850 +f 921/921/921 922/922/922 923/923/923 +f 922/922/922 924/924/924 923/923/923 +f 918/918/918 920/920/920 851/851/851 +f 922/922/922 921/921/921 920/920/920 +f 851/851/851 854/854/854 856/856/856 +f 887/887/887 855/855/855 854/854/854 +f 925/925/925 855/855/855 887/887/887 +f 851/851/851 856/856/856 849/849/849 +f 917/917/917 922/922/922 920/920/920 +f 925/925/925 887/887/887 923/923/923 +f 887/887/887 921/921/921 923/923/923 +f 901/901/901 894/894/894 899/899/899 +f 904/904/904 926/926/926 898/898/898 +f 926/926/926 927/927/927 928/928/928 +f 898/898/898 926/926/926 899/899/899 +f 903/903/903 901/901/901 899/899/899 +f 899/899/899 926/926/926 903/903/903 +f 926/926/926 928/928/928 903/903/903 +f 917/917/917 920/920/920 918/918/918 +f 922/922/922 903/903/903 928/928/928 +f 924/924/924 922/922/922 927/927/927 +f 922/922/922 928/928/928 927/927/927 +f 921/921/921 887/887/887 920/920/920 +f 916/916/916 902/902/902 903/903/903 +f 922/922/922 916/916/916 903/903/903 +f 917/917/917 916/916/916 922/922/922 +f 883/883/883 872/872/872 929/929/929 +f 673/673/673 930/930/930 648/648/648 +f 931/931/931 649/649/649 675/675/675 +f 675/675/675 676/676/676 931/931/931 +f 932/932/932 673/673/673 674/674/674 +f 930/930/930 677/677/677 648/648/648 +f 933/933/933 658/658/658 677/677/677 +f 930/930/930 933/933/933 677/677/677 +f 649/649/649 931/931/931 934/934/934 +f 935/935/935 936/936/936 937/937/937 +f 937/937/937 938/938/938 935/935/935 +f 936/936/936 935/935/935 939/939/939 +f 940/940/940 939/939/939 935/935/935 +f 941/941/941 650/650/650 649/649/649 +f 649/649/649 934/934/934 941/941/941 +f 942/942/942 938/938/938 943/943/943 +f 944/944/944 945/945/945 946/946/946 +f 945/945/945 933/933/933 946/946/946 +f 947/947/947 948/948/948 944/944/944 +f 664/664/664 665/665/665 659/659/659 +f 949/949/949 659/659/659 658/658/658 +f 663/663/663 659/659/659 949/949/949 +f 664/664/664 659/659/659 663/663/663 +f 933/933/933 945/945/945 658/658/658 +f 932/932/932 946/946/946 933/933/933 +f 677/677/677 675/675/675 649/649/649 +f 677/677/677 649/649/649 648/648/648 +f 933/933/933 930/930/930 932/932/932 +f 658/658/658 660/660/660 677/677/677 +f 945/945/945 949/949/949 658/658/658 +f 932/932/932 930/930/930 673/673/673 +f 950/950/950 951/951/951 942/942/942 +f 867/867/867 866/866/866 890/890/890 +f 843/843/843 846/846/846 865/865/865 +f 842/842/842 843/843/843 865/865/865 +f 866/866/866 846/846/846 890/890/890 +f 880/880/880 882/882/882 869/869/869 +f 867/867/867 869/869/869 873/873/873 +f 867/867/867 873/873/873 866/866/866 +f 868/868/868 867/867/867 952/952/952 +f 845/845/845 888/888/888 846/846/846 +f 953/953/953 954/954/954 955/955/955 +f 952/952/952 953/953/953 956/956/956 +f 888/888/888 890/890/890 846/846/846 +f 952/952/952 954/954/954 953/953/953 +f 882/882/882 876/876/876 874/874/874 +f 890/890/890 957/957/957 958/958/958 +f 943/943/943 938/938/938 937/937/937 +f 950/950/950 959/959/959 951/951/951 +f 960/960/960 959/959/959 950/950/950 +f 929/929/929 950/950/950 943/943/943 +f 938/938/938 942/942/942 961/961/961 +f 962/962/962 935/935/935 938/938/938 +f 950/950/950 942/942/942 943/943/943 +f 963/963/963 959/959/959 960/960/960 +f 963/963/963 869/869/869 956/956/956 +f 959/959/959 963/963/963 956/956/956 +f 882/882/882 874/874/874 873/873/873 +f 960/960/960 950/950/950 929/929/929 +f 960/960/960 880/880/880 869/869/869 +f 963/963/963 960/960/960 869/869/869 +f 929/929/929 880/880/880 960/960/960 +f 945/945/945 948/948/948 949/949/949 +f 964/964/964 965/965/965 966/966/966 +f 646/646/646 967/967/967 968/968/968 +f 967/967/967 966/966/966 968/968/968 +f 966/966/966 967/967/967 964/964/964 +f 964/964/964 969/969/969 970/970/970 +f 964/964/964 967/967/967 969/969/969 +f 967/967/967 971/971/971 969/969/969 +f 971/971/971 967/967/967 646/646/646 +f 972/972/972 645/645/645 973/973/973 +f 645/645/645 974/974/974 973/973/973 +f 974/974/974 975/975/975 668/668/668 +f 974/974/974 645/645/645 647/647/647 +f 971/971/971 645/645/645 972/972/972 +f 972/972/972 969/969/969 971/971/971 +f 645/645/645 971/971/971 646/646/646 +f 929/929/929 937/937/937 965/965/965 +f 976/976/976 929/929/929 965/965/965 +f 965/965/965 936/936/936 966/966/966 +f 929/929/929 943/943/943 937/937/937 +f 872/872/872 881/881/881 929/929/929 +f 881/881/881 880/880/880 929/929/929 +f 872/872/872 871/871/871 881/881/881 +f 936/936/936 965/965/965 937/937/937 +f 976/976/976 883/883/883 929/929/929 +f 976/976/976 965/965/965 964/964/964 +f 970/970/970 976/976/976 964/964/964 +f 976/976/976 970/970/970 884/884/884 +f 968/968/968 936/936/936 939/939/939 +f 966/966/966 936/936/936 968/968/968 +f 883/883/883 976/976/976 884/884/884 +f 668/668/668 973/973/973 974/974/974 +f 977/977/977 978/978/978 979/979/979 +f 979/979/979 884/884/884 977/977/977 +f 980/980/980 978/978/978 981/981/981 +f 978/978/978 948/948/948 982/982/982 +f 668/668/668 667/667/667 973/973/973 +f 668/668/668 983/983/983 662/662/662 +f 979/979/979 978/978/978 982/982/982 +f 978/978/978 977/977/977 981/981/981 +f 980/980/980 981/981/981 661/661/661 +f 948/948/948 945/945/945 944/944/944 +f 947/947/947 982/982/982 948/948/948 +f 661/661/661 663/663/663 949/949/949 +f 948/948/948 978/978/978 980/980/980 +f 980/980/980 949/949/949 948/948/948 +f 980/980/980 661/661/661 949/949/949 +f 668/668/668 975/975/975 983/983/983 +f 975/975/975 984/984/984 983/983/983 +f 970/970/970 985/985/985 977/977/977 +f 986/986/986 987/987/987 984/984/984 +f 986/986/986 975/975/975 647/647/647 +f 975/975/975 974/974/974 647/647/647 +f 984/984/984 975/975/975 986/986/986 +f 977/977/977 884/884/884 970/970/970 +f 977/977/977 985/985/985 981/981/981 +f 985/985/985 667/667/667 981/981/981 +f 661/661/661 981/981/981 667/667/667 +f 972/972/972 973/973/973 667/667/667 +f 972/972/972 985/985/985 969/969/969 +f 985/985/985 970/970/970 969/969/969 +f 667/667/667 985/985/985 972/972/972 +f 988/988/988 989/989/989 990/990/990 +f 990/990/990 991/991/991 988/988/988 +f 992/992/992 989/989/989 993/993/993 +f 994/994/994 988/988/988 991/991/991 +f 988/988/988 994/994/994 676/676/676 +f 676/676/676 993/993/993 988/988/988 +f 995/995/995 994/994/994 991/991/991 +f 989/989/989 988/988/988 993/993/993 +f 995/995/995 996/996/996 934/934/934 +f 996/996/996 941/941/941 934/934/934 +f 997/997/997 996/996/996 995/995/995 +f 989/989/989 405/405/405 331/331/331 +f 405/405/405 989/989/989 992/992/992 +f 992/992/992 411/411/411 405/405/405 +f 990/990/990 989/989/989 331/331/331 +f 676/676/676 998/998/998 993/993/993 +f 998/998/998 999/999/999 992/992/992 +f 992/992/992 993/993/993 998/998/998 +f 998/998/998 676/676/676 1000/1000/1000 +f 1001/1001/1001 1002/1002/1002 1003/1003/1003 +f 665/665/665 1000/1000/1000 676/676/676 +f 665/665/665 676/676/676 660/660/660 +f 1000/1000/1000 1004/1004/1004 1005/1005/1005 +f 931/931/931 994/994/994 995/995/995 +f 995/995/995 934/934/934 931/931/931 +f 994/994/994 931/931/931 676/676/676 +f 999/999/999 1006/1006/1006 411/411/411 +f 1006/1006/1006 999/999/999 1001/1001/1001 +f 1001/1001/1001 1003/1003/1003 1006/1006/1006 +f 992/992/992 999/999/999 411/411/411 +f 995/995/995 991/991/991 997/997/997 +f 1007/1007/1007 1008/1008/1008 414/414/414 +f 1009/1009/1009 1007/1007/1007 413/413/413 +f 413/413/413 378/378/378 1009/1009/1009 +f 413/413/413 1007/1007/1007 414/414/414 +f 1010/1010/1010 1008/1008/1008 1011/1011/1011 +f 1008/1008/1008 1007/1007/1007 1012/1012/1012 +f 1012/1012/1012 1011/1011/1011 1008/1008/1008 +f 1012/1012/1012 1007/1007/1007 1013/1013/1013 +f 1014/1014/1014 1015/1015/1015 1016/1016/1016 +f 1017/1017/1017 1016/1016/1016 1015/1015/1015 +f 1015/1015/1015 1011/1011/1011 1017/1017/1017 +f 1016/1016/1016 1018/1018/1018 1014/1014/1014 +f 1007/1007/1007 1009/1009/1009 1013/1013/1013 +f 1018/1018/1018 1016/1016/1016 987/987/987 +f 1016/1016/1016 984/984/984 987/987/987 +f 330/330/330 1019/1019/1019 331/331/331 +f 1019/1019/1019 990/990/990 331/331/331 +f 1020/1020/1020 1019/1019/1019 329/329/329 +f 1019/1019/1019 997/997/997 991/991/991 +f 996/996/996 997/997/997 1020/1020/1020 +f 997/997/997 1019/1019/1019 1020/1020/1020 +f 990/990/990 1019/1019/1019 991/991/991 +f 1019/1019/1019 330/330/330 329/329/329 +f 1008/1008/1008 1010/1010/1010 416/416/416 +f 416/416/416 414/414/414 1008/1008/1008 +f 1015/1015/1015 1010/1010/1010 1011/1011/1011 +f 1010/1010/1010 1021/1021/1021 417/417/417 +f 1021/1021/1021 1010/1010/1010 1015/1015/1015 +f 1015/1015/1015 1014/1014/1014 1021/1021/1021 +f 416/416/416 1010/1010/1010 417/417/417 +f 1002/1002/1002 386/386/386 1003/1003/1003 +f 1022/1022/1022 1023/1023/1023 384/384/384 +f 1024/1024/1024 384/384/384 1023/1023/1023 +f 1023/1023/1023 325/325/325 332/332/332 +f 1025/1025/1025 1022/1022/1022 384/384/384 +f 401/401/401 1022/1022/1022 408/408/408 +f 1022/1022/1022 1025/1025/1025 408/408/408 +f 401/401/401 403/403/403 1022/1022/1022 +f 1024/1024/1024 1023/1023/1023 332/332/332 +f 381/381/381 384/384/384 1024/1024/1024 +f 332/332/332 1026/1026/1026 1024/1024/1024 +f 332/332/332 409/409/409 1026/1026/1026 +f 382/382/382 381/381/381 1024/1024/1024 +f 383/383/383 1025/1025/1025 384/384/384 +f 383/383/383 408/408/408 1025/1025/1025 +f 1026/1026/1026 382/382/382 1024/1024/1024 +f 1027/1027/1027 1028/1028/1028 641/641/641 +f 641/641/641 657/657/657 1027/1027/1027 +f 1022/1022/1022 1028/1028/1028 1023/1023/1023 +f 415/415/415 417/417/417 641/641/641 +f 415/415/415 1028/1028/1028 1022/1022/1022 +f 1022/1022/1022 403/403/403 415/415/415 +f 641/641/641 1028/1028/1028 415/415/415 +f 1028/1028/1028 1027/1027/1027 1023/1023/1023 +f 328/328/328 327/327/327 656/656/656 +f 656/656/656 329/329/329 328/328/328 +f 327/327/327 328/328/328 323/323/323 +f 327/327/327 1027/1027/1027 657/657/657 +f 1027/1027/1027 327/327/327 325/325/325 +f 325/325/325 1023/1023/1023 1027/1027/1027 +f 656/656/656 327/327/327 657/657/657 +f 380/380/380 1029/1029/1029 386/386/386 +f 665/665/665 664/664/664 670/670/670 +f 670/670/670 1005/1005/1005 1004/1004/1004 +f 665/665/665 670/670/670 1004/1004/1004 +f 377/377/377 379/379/379 1030/1030/1030 +f 377/377/377 1031/1031/1031 378/378/378 +f 1031/1031/1031 1009/1009/1009 378/378/378 +f 1030/1030/1030 1031/1031/1031 377/377/377 +f 998/998/998 1005/1005/1005 1002/1002/1002 +f 1001/1001/1001 999/999/999 998/998/998 +f 1001/1001/1001 998/998/998 1002/1002/1002 +f 998/998/998 1000/1000/1000 1005/1005/1005 +f 1004/1004/1004 1000/1000/1000 665/665/665 +f 1002/1002/1002 1005/1005/1005 1030/1030/1030 +f 1030/1030/1030 379/379/379 386/386/386 +f 1002/1002/1002 1030/1030/1030 386/386/386 +f 1003/1003/1003 1029/1029/1029 410/410/410 +f 1029/1029/1029 409/409/409 410/410/410 +f 1003/1003/1003 410/410/410 1006/1006/1006 +f 1029/1029/1029 1026/1026/1026 409/409/409 +f 1029/1029/1029 1003/1003/1003 386/386/386 +f 382/382/382 1029/1029/1029 380/380/380 +f 1029/1029/1029 382/382/382 1026/1026/1026 +f 410/410/410 411/411/411 1006/1006/1006 +f 1031/1031/1031 1030/1030/1030 1005/1005/1005 +f 1009/1009/1009 1031/1031/1031 1032/1032/1032 +f 1032/1032/1032 1013/1013/1013 1009/1009/1009 +f 1032/1032/1032 1031/1031/1031 1005/1005/1005 +f 1032/1032/1032 669/669/669 1013/1013/1013 +f 670/670/670 669/669/669 1032/1032/1032 +f 1032/1032/1032 1005/1005/1005 670/670/670 +f 984/984/984 1016/1016/1016 1017/1017/1017 +f 1033/1033/1033 923/923/923 924/924/924 +f 1034/1034/1034 1035/1035/1035 927/927/927 +f 1035/1035/1035 924/924/924 927/927/927 +f 924/924/924 1035/1035/1035 1033/1033/1033 +f 926/926/926 915/915/915 1036/1036/1036 +f 1037/1037/1037 1036/1036/1036 905/905/905 +f 1038/1038/1038 1036/1036/1036 1037/1037/1037 +f 1039/1039/1039 1035/1035/1035 1034/1034/1034 +f 1040/1040/1040 1038/1038/1038 1041/1041/1041 +f 855/855/855 925/925/925 1033/1033/1033 +f 925/925/925 923/923/923 1033/1033/1033 +f 1040/1040/1040 1039/1039/1039 1038/1038/1038 +f 1034/1034/1034 1038/1038/1038 1039/1039/1039 +f 1042/1042/1042 1043/1043/1043 1040/1040/1040 +f 1039/1039/1039 1040/1040/1040 1043/1043/1043 +f 915/915/915 914/914/914 906/906/906 +f 906/906/906 914/914/914 908/908/908 +f 906/906/906 905/905/905 1036/1036/1036 +f 897/897/897 904/904/904 896/896/896 +f 1037/1037/1037 298/298/298 1044/1044/1044 +f 1044/1044/1044 1038/1038/1038 1037/1037/1037 +f 897/897/897 914/914/914 904/904/904 +f 915/915/915 906/906/906 1036/1036/1036 +f 904/904/904 915/915/915 926/926/926 +f 1034/1034/1034 926/926/926 1036/1036/1036 +f 1036/1036/1036 1038/1038/1038 1034/1034/1034 +f 926/926/926 1034/1034/1034 927/927/927 +f 848/848/848 908/908/908 914/914/914 +f 905/905/905 907/907/907 913/913/913 +f 1045/1045/1045 913/913/913 908/908/908 +f 855/855/855 1033/1033/1033 1043/1043/1043 +f 831/831/831 1046/1046/1046 1047/1047/1047 +f 834/834/834 831/831/831 1047/1047/1047 +f 909/909/909 848/848/848 837/837/837 +f 1047/1047/1047 835/835/835 834/834/834 +f 831/831/831 1048/1048/1048 1046/1046/1046 +f 1049/1049/1049 319/319/319 1048/1048/1048 +f 831/831/831 834/834/834 832/832/832 +f 837/837/837 1050/1050/1050 909/909/909 +f 848/848/848 910/910/910 1051/1051/1051 +f 1052/1052/1052 1051/1051/1051 910/910/910 +f 1047/1047/1047 1052/1052/1052 910/910/910 +f 909/909/909 1047/1047/1047 910/910/910 +f 837/837/837 835/835/835 1050/1050/1050 +f 1050/1050/1050 835/835/835 1047/1047/1047 +f 909/909/909 1050/1050/1050 1047/1047/1047 +f 855/855/855 1053/1053/1053 859/859/859 +f 1053/1053/1053 1054/1054/1054 859/859/859 +f 855/855/855 1043/1043/1043 1053/1053/1053 +f 1042/1042/1042 1040/1040/1040 1055/1055/1055 +f 1043/1043/1043 1042/1042/1042 1053/1053/1053 +f 1033/1033/1033 1035/1035/1035 1039/1039/1039 +f 1033/1033/1033 1039/1039/1039 1043/1043/1043 +f 1055/1055/1055 1056/1056/1056 1042/1042/1042 +f 1056/1056/1056 1049/1049/1049 1054/1054/1054 +f 834/834/834 833/833/833 832/832/832 +f 859/859/859 831/831/831 830/830/830 +f 1049/1049/1049 859/859/859 1054/1054/1054 +f 1053/1053/1053 1042/1042/1042 1054/1054/1054 +f 855/855/855 859/859/859 852/852/852 +f 831/831/831 859/859/859 1048/1048/1048 +f 298/298/298 1037/1037/1037 1057/1057/1057 +f 1055/1055/1055 298/298/298 1056/1056/1056 +f 333/333/333 318/318/318 1056/1056/1056 +f 1042/1042/1042 1056/1056/1056 1054/1054/1054 +f 1041/1041/1041 1055/1055/1055 1040/1040/1040 +f 1041/1041/1041 1038/1038/1038 1044/1044/1044 +f 298/298/298 1041/1041/1041 1044/1044/1044 +f 1055/1055/1055 1041/1041/1041 298/298/298 +f 318/318/318 333/333/333 335/335/335 +f 1049/1049/1049 318/318/318 319/319/319 +f 301/301/301 1048/1048/1048 319/319/319 +f 1046/1046/1046 1058/1058/1058 1047/1047/1047 +f 859/859/859 1049/1049/1049 1048/1048/1048 +f 1056/1056/1056 298/298/298 333/333/333 +f 1056/1056/1056 318/318/318 1049/1049/1049 +f 302/302/302 318/318/318 335/335/335 +f 1059/1059/1059 1017/1017/1017 1011/1011/1011 +f 669/669/669 1059/1059/1059 1012/1012/1012 +f 1012/1012/1012 1013/1013/1013 669/669/669 +f 1012/1012/1012 1059/1059/1059 1011/1011/1011 +f 1017/1017/1017 983/983/983 984/984/984 +f 1017/1017/1017 1059/1059/1059 983/983/983 +f 1059/1059/1059 662/662/662 983/983/983 +f 1059/1059/1059 669/669/669 662/662/662 +f 335/335/335 334/334/334 320/320/320 +f 334/334/334 307/307/307 320/320/320 +f 335/335/335 320/320/320 302/302/302 +f 1060/1060/1060 300/300/300 307/307/307 +f 309/309/309 1061/1061/1061 306/306/306 +f 1060/1060/1060 307/307/307 1062/1062/1062 +f 307/307/307 300/300/300 320/320/320 +f 1048/1048/1048 1058/1058/1058 1046/1046/1046 +f 1061/1061/1061 307/307/307 306/306/306 +f 1061/1061/1061 310/310/310 1045/1045/1045 +f 297/297/297 299/299/299 310/310/310 +f 307/307/307 1061/1061/1061 1062/1062/1062 +f 1045/1045/1045 1063/1063/1063 1061/1061/1061 +f 911/911/911 1064/1064/1064 1063/1063/1063 +f 1063/1063/1063 1062/1062/1062 1061/1061/1061 +f 1061/1061/1061 309/309/309 310/310/310 +f 1045/1045/1045 1057/1057/1057 913/913/913 +f 913/913/913 1057/1057/1057 1037/1037/1037 +f 913/913/913 1037/1037/1037 905/905/905 +f 1045/1045/1045 310/310/310 1057/1057/1057 +f 299/299/299 1057/1057/1057 310/310/310 +f 299/299/299 298/298/298 1057/1057/1057 +f 1063/1063/1063 1045/1045/1045 908/908/908 +f 1052/1052/1052 1047/1047/1047 301/301/301 +f 912/912/912 1051/1051/1051 304/304/304 +f 1051/1051/1051 301/301/301 304/304/304 +f 1051/1051/1051 1052/1052/1052 301/301/301 +f 1047/1047/1047 1058/1058/1058 301/301/301 +f 1058/1058/1058 1048/1048/1048 301/301/301 +f 1064/1064/1064 911/911/911 912/912/912 +f 848/848/848 1051/1051/1051 912/912/912 +f 1064/1064/1064 1060/1060/1060 1063/1063/1063 +f 1060/1060/1060 303/303/303 300/300/300 +f 1063/1063/1063 908/908/908 911/911/911 +f 912/912/912 304/304/304 303/303/303 +f 912/912/912 303/303/303 1064/1064/1064 +f 1064/1064/1064 303/303/303 1060/1060/1060 +f 1060/1060/1060 1062/1062/1062 1063/1063/1063 +f 868/868/868 952/952/952 956/956/956 +f 461/461/461 1065/1065/1065 458/458/458 +f 1066/1066/1066 1067/1067/1067 1068/1068/1068 +f 1069/1069/1069 433/433/433 480/480/480 +f 1067/1067/1067 1065/1065/1065 1068/1068/1068 +f 744/744/744 1067/1067/1067 1066/1066/1066 +f 744/744/744 1066/1066/1066 743/743/743 +f 457/457/457 458/458/458 1065/1065/1065 +f 739/739/739 741/741/741 480/480/480 +f 631/631/631 428/428/428 1070/1070/1070 +f 1071/1071/1071 1070/1070/1070 1072/1072/1072 +f 743/743/743 1066/1066/1066 1073/1073/1073 +f 1069/1069/1069 480/480/480 1074/1074/1074 +f 739/739/739 480/480/480 733/733/733 +f 743/743/743 480/480/480 741/741/741 +f 480/480/480 743/743/743 1072/1072/1072 +f 1065/1065/1065 461/461/461 1075/1075/1075 +f 1076/1076/1076 1077/1077/1077 1078/1078/1078 +f 1079/1079/1079 1076/1076/1076 1078/1078/1078 +f 1080/1080/1080 1081/1081/1081 1068/1068/1068 +f 454/454/454 317/317/317 460/460/460 +f 461/461/461 460/460/460 1082/1082/1082 +f 461/461/461 1078/1078/1078 1075/1075/1075 +f 1081/1081/1081 1083/1083/1083 1068/1068/1068 +f 457/457/457 744/744/744 462/462/462 +f 1067/1067/1067 744/744/744 457/457/457 +f 1067/1067/1067 457/457/457 1065/1065/1065 +f 733/733/733 480/480/480 432/432/432 +f 1083/1083/1083 1073/1073/1073 1068/1068/1068 +f 1068/1068/1068 1073/1073/1073 1066/1066/1066 +f 733/733/733 432/432/432 479/479/479 +f 480/480/480 1072/1072/1072 1074/1074/1074 +f 1084/1084/1084 1085/1085/1085 1086/1086/1086 +f 1087/1087/1087 551/551/551 1088/1088/1088 +f 551/551/551 565/565/565 1088/1088/1088 +f 1086/1086/1086 1085/1085/1085 1089/1089/1089 +f 1084/1084/1084 1090/1090/1090 1085/1085/1085 +f 1090/1090/1090 1084/1084/1084 1091/1091/1091 +f 1085/1085/1085 1090/1090/1090 1092/1092/1092 +f 1093/1093/1093 1087/1087/1087 1091/1091/1091 +f 449/449/449 1094/1094/1094 1093/1093/1093 +f 1093/1093/1093 450/450/450 449/449/449 +f 423/423/423 422/422/422 449/449/449 +f 1084/1084/1084 1086/1086/1086 1095/1095/1095 +f 1084/1084/1084 1096/1096/1096 1093/1093/1093 +f 1091/1091/1091 1084/1084/1084 1093/1093/1093 +f 1088/1088/1088 1090/1090/1090 1091/1091/1091 +f 1069/1069/1069 1070/1070/1070 428/428/428 +f 1071/1071/1071 1097/1097/1097 631/631/631 +f 631/631/631 630/630/630 424/424/424 +f 1069/1069/1069 1074/1074/1074 1070/1070/1070 +f 433/433/433 1069/1069/1069 427/427/427 +f 427/427/427 1069/1069/1069 428/428/428 +f 1070/1070/1070 1074/1074/1074 1072/1072/1072 +f 630/630/630 429/429/429 424/424/424 +f 563/563/563 1098/1098/1098 1088/1088/1088 +f 1090/1090/1090 1088/1088/1088 1099/1099/1099 +f 1099/1099/1099 1092/1092/1092 1090/1090/1090 +f 1088/1088/1088 565/565/565 563/563/563 +f 631/631/631 424/424/424 428/428/428 +f 428/428/428 424/424/424 426/426/426 +f 1091/1091/1091 1087/1087/1087 1088/1088/1088 +f 460/460/460 461/461/461 456/456/456 +f 1100/1100/1100 1101/1101/1101 1102/1102/1102 +f 1103/1103/1103 1102/1102/1102 1104/1104/1104 +f 1102/1102/1102 1105/1105/1105 1104/1104/1104 +f 635/635/635 1100/1100/1100 1102/1102/1102 +f 1106/1106/1106 1104/1104/1104 1105/1105/1105 +f 1071/1071/1071 1100/1100/1100 1097/1097/1097 +f 1070/1070/1070 1071/1071/1071 631/631/631 +f 1103/1103/1103 1107/1107/1107 1102/1102/1102 +f 1102/1102/1102 1107/1107/1107 1108/1108/1108 +f 634/634/634 1102/1102/1102 609/609/609 +f 1108/1108/1108 1109/1109/1109 1110/1110/1110 +f 1102/1102/1102 1108/1108/1108 609/609/609 +f 1097/1097/1097 635/635/635 633/633/633 +f 1097/1097/1097 633/633/633 631/631/631 +f 635/635/635 1102/1102/1102 634/634/634 +f 1083/1083/1083 1111/1111/1111 1101/1101/1101 +f 1065/1065/1065 1075/1075/1075 1080/1080/1080 +f 1077/1077/1077 1081/1081/1081 1080/1080/1080 +f 1083/1083/1083 1081/1081/1081 1111/1111/1111 +f 1073/1073/1073 1100/1100/1100 1071/1071/1071 +f 1073/1073/1073 1071/1071/1071 1072/1072/1072 +f 1080/1080/1080 1068/1068/1068 1065/1065/1065 +f 1077/1077/1077 1075/1075/1075 1078/1078/1078 +f 1111/1111/1111 1106/1106/1106 1105/1105/1105 +f 1081/1081/1081 1077/1077/1077 1111/1111/1111 +f 1101/1101/1101 1111/1111/1111 1105/1105/1105 +f 1073/1073/1073 1083/1083/1083 1101/1101/1101 +f 635/635/635 1097/1097/1097 1100/1100/1100 +f 1101/1101/1101 1100/1100/1100 1073/1073/1073 +f 1101/1101/1101 1105/1105/1105 1102/1102/1102 +f 1108/1108/1108 1110/1110/1110 609/609/609 +f 1112/1112/1112 1113/1113/1113 1085/1085/1085 +f 1085/1085/1085 1092/1092/1092 1112/1112/1112 +f 1089/1089/1089 1113/1113/1113 1114/1114/1114 +f 1085/1085/1085 1113/1113/1113 1089/1089/1089 +f 1112/1112/1112 1115/1115/1115 1114/1114/1114 +f 1116/1116/1116 1098/1098/1098 1117/1117/1117 +f 1118/1118/1118 1119/1119/1119 1117/1117/1117 +f 1113/1113/1113 1112/1112/1112 1114/1114/1114 +f 1120/1120/1120 1121/1121/1121 460/460/460 +f 454/454/454 460/460/460 456/456/456 +f 1121/1121/1121 1082/1082/1082 460/460/460 +f 459/459/459 1120/1120/1120 460/460/460 +f 1114/1114/1114 1115/1115/1115 1122/1122/1122 +f 1114/1114/1114 1122/1122/1122 1089/1089/1089 +f 469/469/469 1120/1120/1120 459/459/459 +f 1123/1123/1123 563/563/563 546/546/546 +f 1098/1098/1098 1123/1123/1123 1124/1124/1124 +f 1098/1098/1098 1124/1124/1124 1117/1117/1117 +f 563/563/563 1123/1123/1123 1098/1098/1098 +f 545/545/545 1123/1123/1123 546/546/546 +f 549/549/549 1118/1118/1118 1124/1124/1124 +f 549/549/549 1124/1124/1124 545/545/545 +f 545/545/545 1124/1124/1124 1123/1123/1123 +f 1098/1098/1098 1099/1099/1099 1088/1088/1088 +f 1112/1112/1112 1116/1116/1116 1117/1117/1117 +f 1112/1112/1112 1117/1117/1117 1115/1115/1115 +f 1098/1098/1098 1116/1116/1116 1099/1099/1099 +f 1117/1117/1117 1124/1124/1124 1118/1118/1118 +f 1099/1099/1099 1116/1116/1116 1092/1092/1092 +f 1116/1116/1116 1112/1112/1112 1092/1092/1092 +f 422/422/422 566/566/566 449/449/449 +f 1125/1125/1125 644/644/644 643/643/643 +f 1126/1126/1126 644/644/644 1125/1125/1125 +f 492/492/492 1127/1127/1127 1128/1128/1128 +f 644/644/644 1126/1126/1126 1129/1129/1129 +f 1130/1130/1130 642/642/642 485/485/485 +f 1130/1130/1130 485/485/485 488/488/488 +f 651/651/651 644/644/644 1129/1129/1129 +f 1128/1128/1128 511/511/511 492/492/492 +f 1128/1128/1128 1127/1127/1127 1131/1131/1131 +f 1127/1127/1127 1132/1132/1132 1131/1131/1131 +f 1132/1132/1132 1133/1133/1133 1131/1131/1131 +f 651/651/651 1129/1129/1129 1132/1132/1132 +f 651/651/651 1127/1127/1127 492/492/492 +f 492/492/492 489/489/489 651/651/651 +f 1132/1132/1132 1127/1127/1127 651/651/651 +f 488/488/488 1134/1134/1134 1135/1135/1135 +f 1136/1136/1136 1135/1135/1135 1134/1134/1134 +f 1134/1134/1134 488/488/488 510/510/510 +f 1134/1134/1134 1137/1137/1137 1136/1136/1136 +f 1138/1138/1138 1139/1139/1139 500/500/500 +f 508/508/508 1140/1140/1140 509/509/509 +f 1134/1134/1134 509/509/509 1141/1141/1141 +f 509/509/509 1134/1134/1134 510/510/510 +f 643/643/643 1135/1135/1135 1142/1142/1142 +f 485/485/485 642/642/642 489/489/489 +f 642/642/642 651/651/651 489/489/489 +f 1142/1142/1142 1135/1135/1135 1136/1136/1136 +f 642/642/642 1130/1130/1130 643/643/643 +f 1130/1130/1130 1135/1135/1135 643/643/643 +f 488/488/488 1135/1135/1135 1130/1130/1130 +f 1126/1126/1126 1133/1133/1133 1129/1129/1129 +f 1143/1143/1143 1144/1144/1144 1145/1145/1145 +f 1146/1146/1146 1143/1143/1143 1145/1145/1145 +f 284/284/284 281/281/281 1147/1147/1147 +f 1148/1148/1148 1149/1149/1149 1144/1144/1144 +f 1144/1144/1144 1150/1150/1150 1148/1148/1148 +f 1144/1144/1144 1151/1151/1151 466/466/466 +f 1148/1148/1148 1152/1152/1152 1149/1149/1149 +f 281/281/281 280/280/280 1147/1147/1147 +f 467/467/467 466/466/466 1151/1151/1151 +f 1144/1144/1144 1143/1143/1143 1151/1151/1151 +f 467/467/467 1153/1153/1153 468/468/468 +f 1147/1147/1147 1144/1144/1144 466/466/466 +f 284/284/284 1147/1147/1147 466/466/466 +f 284/284/284 466/466/466 468/468/468 +f 1147/1147/1147 1150/1150/1150 1144/1144/1144 +f 1152/1152/1152 520/520/520 511/511/511 +f 1149/1149/1149 1152/1152/1152 1131/1131/1131 +f 1152/1152/1152 1128/1128/1128 1131/1131/1131 +f 1128/1128/1128 1152/1152/1152 511/511/511 +f 1133/1133/1133 1132/1132/1132 1129/1129/1129 +f 520/520/520 1152/1152/1152 1148/1148/1148 +f 1148/1148/1148 517/517/517 520/520/520 +f 1149/1149/1149 1146/1146/1146 1145/1145/1145 +f 1147/1147/1147 280/280/280 516/516/516 +f 1148/1148/1148 1150/1150/1150 517/517/517 +f 1150/1150/1150 516/516/516 517/517/517 +f 516/516/516 1150/1150/1150 1147/1147/1147 +f 1149/1149/1149 1145/1145/1145 1144/1144/1144 +f 1131/1131/1131 1146/1146/1146 1149/1149/1149 +f 1133/1133/1133 1146/1146/1146 1131/1131/1131 +f 1139/1139/1139 1140/1140/1140 500/500/500 +f 961/961/961 1154/1154/1154 1155/1155/1155 +f 1156/1156/1156 962/962/962 1157/1157/1157 +f 962/962/962 1155/1155/1155 1157/1157/1157 +f 1155/1155/1155 962/962/962 961/961/961 +f 1155/1155/1155 1158/1158/1158 1159/1159/1159 +f 1160/1160/1160 1158/1158/1158 1154/1154/1154 +f 1158/1158/1158 1155/1155/1155 1154/1154/1154 +f 935/935/935 962/962/962 1156/1156/1156 +f 1161/1161/1161 543/543/543 526/526/526 +f 1162/1162/1162 1161/1161/1161 1160/1160/1160 +f 1160/1160/1160 1154/1154/1154 1162/1162/1162 +f 1160/1160/1160 1161/1161/1161 526/526/526 +f 1156/1156/1156 940/940/940 935/935/935 +f 543/543/543 1161/1161/1161 1163/1163/1163 +f 1163/1163/1163 497/497/497 543/543/543 +f 451/451/451 1096/1096/1096 452/452/452 +f 1093/1093/1093 1096/1096/1096 451/451/451 +f 451/451/451 450/450/450 1093/1093/1093 +f 1094/1094/1094 1087/1087/1087 1093/1093/1093 +f 566/566/566 1094/1094/1094 449/449/449 +f 1094/1094/1094 566/566/566 1087/1087/1087 +f 566/566/566 551/551/551 1087/1087/1087 +f 1096/1096/1096 1164/1164/1164 452/452/452 +f 1159/1159/1159 1158/1158/1158 528/528/528 +f 1158/1158/1158 525/525/525 528/528/528 +f 1155/1155/1155 1159/1159/1159 1157/1157/1157 +f 1160/1160/1160 526/526/526 525/525/525 +f 1164/1164/1164 1096/1096/1096 1084/1084/1084 +f 1084/1084/1084 1095/1095/1095 1164/1164/1164 +f 525/525/525 1158/1158/1158 1160/1160/1160 +f 1163/1163/1163 1161/1161/1161 1165/1165/1165 +f 1166/1166/1166 1167/1167/1167 1168/1168/1168 +f 1169/1169/1169 1167/1167/1167 1170/1170/1170 +f 1171/1171/1171 953/953/953 1170/1170/1170 +f 1166/1166/1166 1170/1170/1170 1167/1167/1167 +f 1166/1166/1166 1168/1168/1168 1165/1165/1165 +f 1168/1168/1168 1163/1163/1163 1165/1165/1165 +f 1167/1167/1167 1172/1172/1172 1168/1168/1168 +f 499/499/499 1172/1172/1172 500/500/500 +f 500/500/500 508/508/508 507/507/507 +f 1140/1140/1140 508/508/508 500/500/500 +f 1140/1140/1140 1173/1173/1173 509/509/509 +f 1172/1172/1172 1167/1167/1167 1138/1138/1138 +f 498/498/498 500/500/500 507/507/507 +f 1172/1172/1172 499/499/499 497/497/497 +f 500/500/500 1172/1172/1172 1138/1138/1138 +f 962/962/962 938/938/938 961/961/961 +f 1165/1165/1165 942/942/942 951/951/951 +f 1171/1171/1171 1166/1166/1166 1165/1165/1165 +f 1165/1165/1165 1162/1162/1162 942/942/942 +f 1161/1161/1161 1162/1162/1162 1165/1165/1165 +f 1162/1162/1162 961/961/961 942/942/942 +f 1162/1162/1162 1154/1154/1154 961/961/961 +f 959/959/959 1171/1171/1171 1165/1165/1165 +f 869/869/869 868/868/868 956/956/956 +f 1163/1163/1163 1168/1168/1168 497/497/497 +f 1168/1168/1168 1172/1172/1172 497/497/497 +f 953/953/953 1171/1171/1171 956/956/956 +f 1165/1165/1165 951/951/951 959/959/959 +f 1166/1166/1166 1171/1171/1171 1170/1170/1170 +f 959/959/959 956/956/956 1171/1171/1171 +f 1174/1174/1174 1175/1175/1175 1176/1176/1176 +f 1177/1177/1177 1178/1178/1178 1174/1174/1174 +f 1179/1179/1179 879/879/879 1175/1175/1175 +f 1175/1175/1175 1180/1180/1180 1176/1176/1176 +f 1179/1179/1179 870/870/870 879/879/879 +f 1174/1174/1174 1176/1176/1176 1142/1142/1142 +f 1177/1177/1177 1174/1174/1174 1142/1142/1142 +f 1174/1174/1174 1179/1179/1179 1175/1175/1175 +f 1176/1176/1176 1180/1180/1180 1181/1181/1181 +f 1181/1181/1181 1182/1182/1182 1176/1176/1176 +f 979/979/979 1180/1180/1180 884/884/884 +f 1142/1142/1142 1176/1176/1176 1182/1182/1182 +f 879/879/879 884/884/884 1175/1175/1175 +f 1142/1142/1142 1182/1182/1182 643/643/643 +f 1136/1136/1136 1177/1177/1177 1142/1142/1142 +f 1178/1178/1178 1183/1183/1183 886/886/886 +f 1183/1183/1183 863/863/863 886/886/886 +f 1178/1178/1178 1184/1184/1184 1183/1183/1183 +f 1183/1183/1183 838/838/838 1185/1185/1185 +f 1186/1186/1186 838/838/838 1183/1183/1183 +f 1141/1141/1141 1186/1186/1186 1184/1184/1184 +f 1183/1183/1183 1185/1185/1185 863/863/863 +f 1178/1178/1178 886/886/886 885/885/885 +f 1177/1177/1177 1184/1184/1184 1178/1178/1178 +f 1179/1179/1179 1178/1178/1178 870/870/870 +f 1178/1178/1178 885/885/885 870/870/870 +f 1178/1178/1178 1179/1179/1179 1174/1174/1174 +f 1177/1177/1177 1136/1136/1136 1137/1137/1137 +f 1184/1184/1184 1177/1177/1177 1137/1137/1137 +f 1184/1184/1184 1137/1137/1137 1141/1141/1141 +f 1180/1180/1180 1175/1175/1175 884/884/884 +f 1187/1187/1187 1146/1146/1146 1188/1188/1188 +f 1146/1146/1146 1189/1189/1189 1188/1188/1188 +f 1190/1190/1190 1146/1146/1146 1187/1187/1187 +f 1133/1133/1133 1189/1189/1189 1146/1146/1146 +f 947/947/947 944/944/944 1191/1191/1191 +f 1188/1188/1188 1192/1192/1192 944/944/944 +f 944/944/944 946/946/946 1188/1188/1188 +f 1187/1187/1187 1193/1193/1193 1190/1190/1190 +f 1194/1194/1194 1195/1195/1195 467/467/467 +f 1196/1196/1196 1194/1194/1194 1190/1190/1190 +f 1146/1146/1146 1190/1190/1190 1143/1143/1143 +f 1194/1194/1194 1143/1143/1143 1190/1190/1190 +f 932/932/932 1187/1187/1187 946/946/946 +f 1187/1187/1187 1188/1188/1188 946/946/946 +f 1193/1193/1193 1187/1187/1187 932/932/932 +f 1126/1126/1126 1125/1125/1125 1191/1191/1191 +f 1181/1181/1181 1197/1197/1197 1125/1125/1125 +f 1125/1125/1125 1182/1182/1182 1181/1181/1181 +f 1125/1125/1125 1197/1197/1197 1191/1191/1191 +f 1181/1181/1181 1180/1180/1180 979/979/979 +f 979/979/979 982/982/982 1181/1181/1181 +f 1125/1125/1125 643/643/643 1182/1182/1182 +f 947/947/947 1197/1197/1197 982/982/982 +f 1189/1189/1189 1192/1192/1192 1188/1188/1188 +f 1126/1126/1126 1191/1191/1191 1192/1192/1192 +f 944/944/944 1192/1192/1192 1191/1191/1191 +f 1189/1189/1189 1133/1133/1133 1192/1192/1192 +f 1197/1197/1197 1181/1181/1181 982/982/982 +f 1191/1191/1191 1197/1197/1197 947/947/947 +f 1133/1133/1133 1126/1126/1126 1192/1192/1192 +f 1186/1186/1186 1183/1183/1183 1184/1184/1184 +f 900/900/900 902/902/902 1198/1198/1198 +f 1139/1139/1139 1138/1138/1138 1199/1199/1199 +f 1138/1138/1138 1167/1167/1167 1199/1199/1199 +f 1198/1198/1198 1200/1200/1200 900/900/900 +f 1201/1201/1201 1200/1200/1200 955/955/955 +f 900/900/900 1200/1200/1200 889/889/889 +f 1200/1200/1200 1201/1201/1201 889/889/889 +f 1139/1139/1139 1199/1199/1199 919/919/919 +f 1198/1198/1198 902/902/902 916/916/916 +f 1202/1202/1202 1203/1203/1203 1204/1204/1204 +f 1205/1205/1205 1140/1140/1140 1139/1139/1139 +f 916/916/916 919/919/919 1206/1206/1206 +f 1199/1199/1199 1206/1206/1206 919/919/919 +f 1139/1139/1139 919/919/919 1207/1207/1207 +f 1198/1198/1198 916/916/916 1206/1206/1206 +f 952/952/952 867/867/867 890/890/890 +f 952/952/952 890/890/890 958/958/958 +f 889/889/889 957/957/957 890/890/890 +f 1201/1201/1201 955/955/955 958/958/958 +f 958/958/958 954/954/954 952/952/952 +f 954/954/954 958/958/958 955/955/955 +f 958/958/958 957/957/957 1201/1201/1201 +f 1201/1201/1201 957/957/957 889/889/889 +f 1199/1199/1199 955/955/955 1206/1206/1206 +f 955/955/955 1200/1200/1200 1206/1206/1206 +f 1198/1198/1198 1206/1206/1206 1200/1200/1200 +f 953/953/953 1169/1169/1169 1170/1170/1170 +f 1169/1169/1169 955/955/955 1199/1199/1199 +f 1199/1199/1199 1167/1167/1167 1169/1169/1169 +f 953/953/953 955/955/955 1169/1169/1169 +f 1139/1139/1139 1207/1207/1207 1205/1205/1205 +f 1204/1204/1204 857/857/857 861/861/861 +f 857/857/857 849/849/849 861/861/861 +f 1208/1208/1208 860/860/860 1209/1209/1209 +f 1208/1208/1208 861/861/861 860/860/860 +f 1173/1173/1173 1202/1202/1202 1141/1141/1141 +f 1173/1173/1173 1141/1141/1141 509/509/509 +f 1209/1209/1209 1186/1186/1186 1208/1208/1208 +f 1209/1209/1209 860/860/860 840/840/840 +f 864/864/864 863/863/863 1185/1185/1185 +f 1134/1134/1134 1141/1141/1141 1137/1137/1137 +f 1186/1186/1186 1209/1209/1209 838/838/838 +f 838/838/838 864/864/864 1185/1185/1185 +f 840/840/840 838/838/838 1209/1209/1209 +f 832/832/832 840/840/840 860/860/860 +f 838/838/838 839/839/839 864/864/864 +f 1210/1210/1210 1205/1205/1205 1207/1207/1207 +f 918/918/918 1210/1210/1210 919/919/919 +f 1202/1202/1202 1173/1173/1173 1203/1203/1203 +f 919/919/919 1210/1210/1210 1207/1207/1207 +f 850/850/850 857/857/857 1204/1204/1204 +f 1205/1205/1205 1210/1210/1210 850/850/850 +f 1205/1205/1205 850/850/850 1204/1204/1204 +f 1186/1186/1186 1202/1202/1202 1208/1208/1208 +f 1203/1203/1203 1205/1205/1205 1204/1204/1204 +f 1210/1210/1210 918/918/918 850/850/850 +f 1186/1186/1186 1141/1141/1141 1202/1202/1202 +f 1203/1203/1203 1140/1140/1140 1205/1205/1205 +f 1140/1140/1140 1203/1203/1203 1173/1173/1173 +f 1208/1208/1208 1202/1202/1202 1204/1204/1204 +f 1204/1204/1204 861/861/861 1208/1208/1208 +f 1196/1196/1196 1190/1190/1190 1193/1193/1193 +f 1117/1117/1117 1119/1119/1119 1115/1115/1115 +f 1211/1211/1211 400/400/400 395/395/395 +f 1212/1212/1212 1211/1211/1211 395/395/395 +f 1119/1119/1119 1211/1211/1211 1212/1212/1212 +f 1118/1118/1118 390/390/390 1213/1213/1213 +f 400/400/400 1213/1213/1213 390/390/390 +f 388/388/388 387/387/387 391/391/391 +f 1212/1212/1212 395/395/395 396/396/396 +f 1115/1115/1115 1212/1212/1212 1122/1122/1122 +f 396/396/396 393/393/393 397/397/397 +f 469/469/469 1214/1214/1214 666/666/666 +f 1212/1212/1212 396/396/396 1122/1122/1122 +f 1119/1119/1119 1212/1212/1212 1115/1115/1115 +f 395/395/395 400/400/400 391/391/391 +f 391/391/391 387/387/387 392/392/392 +f 1110/1110/1110 610/610/610 609/609/609 +f 612/612/612 611/611/611 1215/1215/1215 +f 611/611/611 1110/1110/1110 1215/1215/1215 +f 1110/1110/1110 611/611/611 610/610/610 +f 1216/1216/1216 1217/1217/1217 1218/1218/1218 +f 1219/1219/1219 1220/1220/1220 1221/1221/1221 +f 1221/1221/1221 1222/1222/1222 1219/1219/1219 +f 1219/1219/1219 606/606/606 612/612/612 +f 1118/1118/1118 1213/1213/1213 1119/1119/1119 +f 1119/1119/1119 1213/1213/1213 400/400/400 +f 1119/1119/1119 400/400/400 1211/1211/1211 +f 549/549/549 390/390/390 1118/1118/1118 +f 612/612/612 1215/1215/1215 1219/1219/1219 +f 597/597/597 606/606/606 1222/1222/1222 +f 606/606/606 1219/1219/1219 1222/1222/1222 +f 1214/1214/1214 589/589/589 586/586/586 +f 1223/1223/1223 1217/1217/1217 1224/1224/1224 +f 1077/1077/1077 1080/1080/1080 1075/1075/1075 +f 1225/1225/1225 1076/1076/1076 1079/1079/1079 +f 1076/1076/1076 1225/1225/1225 1216/1216/1216 +f 722/722/722 1226/1226/1226 724/724/724 +f 1226/1226/1226 722/722/722 1225/1225/1225 +f 722/722/722 1224/1224/1224 1225/1225/1225 +f 1226/1226/1226 1225/1225/1225 1079/1079/1079 +f 1106/1106/1106 1227/1227/1227 1104/1104/1104 +f 1227/1227/1227 1228/1228/1228 1104/1104/1104 +f 1073/1073/1073 1072/1072/1072 743/743/743 +f 1077/1077/1077 1076/1076/1076 1227/1227/1227 +f 1076/1076/1076 1216/1216/1216 1227/1227/1227 +f 1077/1077/1077 1106/1106/1106 1111/1111/1111 +f 1106/1106/1106 1077/1077/1077 1227/1227/1227 +f 1121/1121/1121 666/666/666 573/573/573 +f 1082/1082/1082 1121/1121/1121 573/573/573 +f 461/461/461 1082/1082/1082 1229/1229/1229 +f 469/469/469 666/666/666 1120/1120/1120 +f 469/469/469 589/589/589 1214/1214/1214 +f 666/666/666 1214/1214/1214 586/586/586 +f 1121/1121/1121 1120/1120/1120 666/666/666 +f 1229/1229/1229 1082/1082/1082 575/575/575 +f 461/461/461 1229/1229/1229 1078/1078/1078 +f 1229/1229/1229 1079/1079/1079 1078/1078/1078 +f 724/724/724 1226/1226/1226 729/729/729 +f 1226/1226/1226 1229/1229/1229 729/729/729 +f 1082/1082/1082 573/573/573 575/575/575 +f 1229/1229/1229 575/575/575 729/729/729 +f 1229/1229/1229 1226/1226/1226 1079/1079/1079 +f 1221/1221/1221 1220/1220/1220 1218/1218/1218 +f 1230/1230/1230 722/722/722 728/728/728 +f 725/725/725 1230/1230/1230 728/728/728 +f 1230/1230/1230 1223/1223/1223 1224/1224/1224 +f 598/598/598 1231/1231/1231 248/248/248 +f 1232/1232/1232 598/598/598 248/248/248 +f 247/247/247 1232/1232/1232 248/248/248 +f 247/247/247 590/590/590 1232/1232/1232 +f 1230/1230/1230 1224/1224/1224 722/722/722 +f 1233/1233/1233 731/731/731 248/248/248 +f 1233/1233/1233 248/248/248 1234/1234/1234 +f 1224/1224/1224 1216/1216/1216 1225/1225/1225 +f 248/248/248 731/731/731 246/246/246 +f 725/725/725 731/731/731 1233/1233/1233 +f 1230/1230/1230 725/725/725 1233/1233/1233 +f 1230/1230/1230 1233/1233/1233 1223/1223/1223 +f 467/467/467 1235/1235/1235 1153/1153/1153 +f 1143/1143/1143 1194/1194/1194 467/467/467 +f 1143/1143/1143 467/467/467 1151/1151/1151 +f 467/467/467 1195/1195/1195 1235/1235/1235 +f 1196/1196/1196 674/674/674 1195/1195/1195 +f 674/674/674 1196/1196/1196 1193/1193/1193 +f 932/932/932 674/674/674 1193/1193/1193 +f 1195/1195/1195 1236/1236/1236 1235/1235/1235 +f 595/595/595 598/598/598 1232/1232/1232 +f 1231/1231/1231 598/598/598 597/597/597 +f 597/597/597 1222/1222/1222 1231/1231/1231 +f 1232/1232/1232 590/590/590 595/595/595 +f 1195/1195/1195 674/674/674 1236/1236/1236 +f 1194/1194/1194 1196/1196/1196 1195/1195/1195 +f 672/672/672 1236/1236/1236 674/674/674 +f 1223/1223/1223 1234/1234/1234 1217/1217/1217 +f 1224/1224/1224 1217/1217/1217 1216/1216/1216 +f 1237/1237/1237 1109/1109/1109 1108/1108/1108 +f 1108/1108/1108 1107/1107/1107 1237/1237/1237 +f 1238/1238/1238 1228/1228/1228 1227/1227/1227 +f 1238/1238/1238 1239/1239/1239 1237/1237/1237 +f 1238/1238/1238 1216/1216/1216 1239/1239/1239 +f 1216/1216/1216 1218/1218/1218 1239/1239/1239 +f 1240/1240/1240 1109/1109/1109 1239/1239/1239 +f 1220/1220/1220 1219/1219/1219 1215/1215/1215 +f 1218/1218/1218 1220/1220/1220 1240/1240/1240 +f 1240/1240/1240 1239/1239/1239 1218/1218/1218 +f 1240/1240/1240 1220/1220/1220 1215/1215/1215 +f 1109/1109/1109 1237/1237/1237 1239/1239/1239 +f 1110/1110/1110 1109/1109/1109 1240/1240/1240 +f 1240/1240/1240 1215/1215/1215 1110/1110/1110 +f 1223/1223/1223 1233/1233/1233 1234/1234/1234 +f 1231/1231/1231 1241/1241/1241 248/248/248 +f 1221/1221/1221 1241/1241/1241 1222/1222/1222 +f 248/248/248 1241/1241/1241 1234/1234/1234 +f 1234/1234/1234 1241/1241/1241 1221/1221/1221 +f 1217/1217/1217 1234/1234/1234 1221/1221/1221 +f 1217/1217/1217 1221/1221/1221 1218/1218/1218 +f 1241/1241/1241 1231/1231/1231 1222/1222/1222 +f 1238/1238/1238 1242/1242/1242 1228/1228/1228 +f 1238/1238/1238 1227/1227/1227 1216/1216/1216 +f 1237/1237/1237 1242/1242/1242 1238/1238/1238 +f 1103/1103/1103 1104/1104/1104 1228/1228/1228 +f 1103/1103/1103 1242/1242/1242 1107/1107/1107 +f 1242/1242/1242 1237/1237/1237 1107/1107/1107 +f 1228/1228/1228 1242/1242/1242 1103/1103/1103 +f 1243/1243/1243 1244/1244/1244 1245/1245/1245 +f 1246/1246/1246 1243/1243/1243 1247/1247/1247 +f 1243/1243/1243 1248/1248/1248 1249/1249/1249 +f 1250/1250/1250 1245/1245/1245 1244/1244/1244 +f 1243/1243/1243 1246/1246/1246 1248/1248/1248 +f 1246/1246/1246 1251/1251/1251 1252/1252/1252 +f 1243/1243/1243 1245/1245/1245 1247/1247/1247 +f 1252/1252/1252 1248/1248/1248 1246/1246/1246 +f 1253/1253/1253 1254/1254/1254 1252/1252/1252 +f 1254/1254/1254 1255/1255/1255 1252/1252/1252 +f 1256/1256/1256 1255/1255/1255 1257/1257/1257 +f 1254/1254/1254 1258/1258/1258 1255/1255/1255 +f 1254/1254/1254 1259/1259/1259 1258/1258/1258 +f 1244/1244/1244 1243/1243/1243 1249/1249/1249 +f 1260/1260/1260 1261/1261/1261 1262/1262/1262 +f 1254/1254/1254 1253/1253/1253 1259/1259/1259 +f 1251/1251/1251 1253/1253/1253 1252/1252/1252 +f 1263/1263/1263 1264/1264/1264 1265/1265/1265 +f 1266/1266/1266 1265/1265/1265 1267/1267/1267 +f 1247/1247/1247 1268/1268/1268 1266/1266/1266 +f 1265/1265/1265 1266/1266/1266 1268/1268/1268 +f 1269/1269/1269 1270/1270/1270 1271/1271/1271 +f 1270/1270/1270 1265/1265/1265 1268/1268/1268 +f 1265/1265/1265 1264/1264/1264 1267/1267/1267 +f 1272/1272/1272 1270/1270/1270 1268/1268/1268 +f 1251/1251/1251 1266/1266/1266 1267/1267/1267 +f 1259/1259/1259 1261/1261/1261 1273/1273/1273 +f 1247/1247/1247 1266/1266/1266 1246/1246/1246 +f 1251/1251/1251 1246/1246/1246 1266/1266/1266 +f 1274/1274/1274 1268/1268/1268 1245/1245/1245 +f 1272/1272/1272 1268/1268/1268 1274/1274/1274 +f 1250/1250/1250 1274/1274/1274 1245/1245/1245 +f 1268/1268/1268 1247/1247/1247 1245/1245/1245 +f 1275/1275/1275 1257/1257/1257 1276/1276/1276 +f 1277/1277/1277 1278/1278/1278 1279/1279/1279 +f 1280/1280/1280 1277/1277/1277 1279/1279/1279 +f 1281/1281/1281 1282/1282/1282 1277/1277/1277 +f 1281/1281/1281 1277/1277/1277 1280/1280/1280 +f 234/234/234 1283/1283/1283 1284/1284/1284 +f 1285/1285/1285 237/237/237 1286/1286/1286 +f 1282/1282/1282 1278/1278/1278 1277/1277/1277 +f 1287/1287/1287 1288/1288/1288 1289/1289/1289 +f 1290/1290/1290 1291/1291/1291 1292/1292/1292 +f 1291/1291/1291 1280/1280/1280 1279/1279/1279 +f 1293/1293/1293 1292/1292/1292 1294/1294/1294 +f 1295/1295/1295 1292/1292/1292 1296/1296/1296 +f 1294/1294/1294 1278/1278/1278 1297/1297/1297 +f 1298/1298/1298 1294/1294/1294 1297/1297/1297 +f 1296/1296/1296 1292/1292/1292 1293/1293/1293 +f 1278/1278/1278 1294/1294/1294 1279/1279/1279 +f 1276/1276/1276 1299/1299/1299 254/254/254 +f 1300/1300/1300 1256/1256/1256 1301/1301/1301 +f 1256/1256/1256 1257/1257/1257 1301/1301/1301 +f 1299/1299/1299 1258/1258/1258 1286/1286/1286 +f 1299/1299/1299 1286/1286/1286 254/254/254 +f 1252/1252/1252 1255/1255/1255 1248/1248/1248 +f 1256/1256/1256 1248/1248/1248 1255/1255/1255 +f 1256/1256/1256 1300/1300/1300 1248/1248/1248 +f 1248/1248/1248 1300/1300/1300 1249/1249/1249 +f 1255/1255/1255 1258/1258/1258 1276/1276/1276 +f 1257/1257/1257 1255/1255/1255 1276/1276/1276 +f 1275/1275/1275 282/282/282 284/284/284 +f 1301/1301/1301 1257/1257/1257 1275/1275/1275 +f 1299/1299/1299 1276/1276/1276 1258/1258/1258 +f 1258/1258/1258 1259/1259/1259 1286/1286/1286 +f 282/282/282 1276/1276/1276 254/254/254 +f 1275/1275/1275 1276/1276/1276 282/282/282 +f 1302/1302/1302 1303/1303/1303 1304/1304/1304 +f 1303/1303/1303 1305/1305/1305 1304/1304/1304 +f 1306/1306/1306 1305/1305/1305 1307/1307/1307 +f 1303/1303/1303 1307/1307/1307 1305/1305/1305 +f 1308/1308/1308 1309/1309/1309 1310/1310/1310 +f 1311/1311/1311 1310/1310/1310 1309/1309/1309 +f 1310/1310/1310 1311/1311/1311 1312/1312/1312 +f 1311/1311/1311 1313/1313/1313 1312/1312/1312 +f 1314/1314/1314 1315/1315/1315 1316/1316/1316 +f 1315/1315/1315 1317/1317/1317 1316/1316/1316 +f 1318/1318/1318 1317/1317/1317 1319/1319/1319 +f 1315/1315/1315 1319/1319/1319 1317/1317/1317 +f 1307/1307/1307 1303/1303/1303 1318/1318/1318 +f 1303/1303/1303 1317/1317/1317 1318/1318/1318 +f 1316/1316/1316 1317/1317/1317 1302/1302/1302 +f 1303/1303/1303 1302/1302/1302 1317/1317/1317 +f 1320/1320/1320 1311/1311/1311 1321/1321/1321 +f 1322/1322/1322 1323/1323/1323 1324/1324/1324 +f 1325/1325/1325 1326/1326/1326 1308/1308/1308 +f 1322/1322/1322 1327/1327/1327 1328/1328/1328 +f 1329/1329/1329 1324/1324/1324 1323/1323/1323 +f 1326/1326/1326 1325/1325/1325 527/527/527 +f 1326/1326/1326 527/527/527 1330/1330/1330 +f 1326/1326/1326 1309/1309/1309 1308/1308/1308 +f 528/528/528 527/527/527 1325/1325/1325 +f 1311/1311/1311 1320/1320/1320 1313/1313/1313 +f 1320/1320/1320 1322/1322/1322 1331/1331/1331 +f 1311/1311/1311 1309/1309/1309 1321/1321/1321 +f 1331/1331/1331 1313/1313/1313 1320/1320/1320 +f 1322/1322/1322 1320/1320/1320 1327/1327/1327 +f 1323/1323/1323 1322/1322/1322 1328/1328/1328 +f 1322/1322/1322 1324/1324/1324 1331/1331/1331 +f 1321/1321/1321 1327/1327/1327 1320/1320/1320 +f 1315/1315/1315 1324/1324/1324 1329/1329/1329 +f 1332/1332/1332 1333/1333/1333 1334/1334/1334 +f 1335/1335/1335 1332/1332/1332 1334/1334/1334 +f 1271/1271/1271 1336/1336/1336 1334/1334/1334 +f 1336/1336/1336 1335/1335/1335 1334/1334/1334 +f 1312/1312/1312 1313/1313/1313 1337/1337/1337 +f 1338/1338/1338 1337/1337/1337 1313/1313/1313 +f 1312/1312/1312 1337/1337/1337 1339/1339/1339 +f 1339/1339/1339 1337/1337/1337 1340/1340/1340 +f 1334/1334/1334 1269/1269/1269 1271/1271/1271 +f 1265/1265/1265 1269/1269/1269 1263/1263/1263 +f 1265/1265/1265 1270/1270/1270 1269/1269/1269 +f 1334/1334/1334 1333/1333/1333 1269/1269/1269 +f 1337/1337/1337 1332/1332/1332 1335/1335/1335 +f 1336/1336/1336 1341/1341/1341 1335/1335/1335 +f 1269/1269/1269 1333/1333/1333 1263/1263/1263 +f 1342/1342/1342 1341/1341/1341 1336/1336/1336 +f 1314/1314/1314 1338/1338/1338 1331/1331/1331 +f 1343/1343/1343 1302/1302/1302 1344/1344/1344 +f 1263/1263/1263 1333/1333/1333 1344/1344/1344 +f 1343/1343/1343 1345/1345/1345 1316/1316/1316 +f 1304/1304/1304 1344/1344/1344 1302/1302/1302 +f 1315/1315/1315 1314/1314/1314 1324/1324/1324 +f 1319/1319/1319 1315/1315/1315 1329/1329/1329 +f 1343/1343/1343 1344/1344/1344 1333/1333/1333 +f 1331/1331/1331 1324/1324/1324 1314/1314/1314 +f 1338/1338/1338 1314/1314/1314 1345/1345/1345 +f 1337/1337/1337 1338/1338/1338 1332/1332/1332 +f 1338/1338/1338 1313/1313/1313 1331/1331/1331 +f 1316/1316/1316 1345/1345/1345 1314/1314/1314 +f 1343/1343/1343 1333/1333/1333 1345/1345/1345 +f 1302/1302/1302 1343/1343/1343 1316/1316/1316 +f 1338/1338/1338 1345/1345/1345 1332/1332/1332 +f 1332/1332/1332 1345/1345/1345 1333/1333/1333 +f 1346/1346/1346 1347/1347/1347 1295/1295/1295 +f 234/234/234 237/237/237 1348/1348/1348 +f 1349/1349/1349 1350/1350/1350 1283/1283/1283 +f 245/245/245 234/234/234 1284/1284/1284 +f 1283/1283/1283 1351/1351/1351 1284/1284/1284 +f 1350/1350/1350 1352/1352/1352 1283/1283/1283 +f 1353/1353/1353 1354/1354/1354 1349/1349/1349 +f 1348/1348/1348 1283/1283/1283 234/234/234 +f 1351/1351/1351 1283/1283/1283 1352/1352/1352 +f 1355/1355/1355 1356/1356/1356 1357/1357/1357 +f 1357/1357/1357 1358/1358/1358 1355/1355/1355 +f 1295/1295/1295 1347/1347/1347 1290/1290/1290 +f 1295/1295/1295 1358/1358/1358 1357/1357/1357 +f 1359/1359/1359 1360/1360/1360 1355/1355/1355 +f 247/247/247 246/246/246 1361/1361/1361 +f 1355/1355/1355 1358/1358/1358 1359/1359/1359 +f 1360/1360/1360 1356/1356/1356 1355/1355/1355 +f 1350/1350/1350 1349/1349/1349 1354/1354/1354 +f 1261/1261/1261 1353/1353/1353 1349/1349/1349 +f 1273/1273/1273 1261/1261/1261 1349/1349/1349 +f 1273/1273/1273 1349/1349/1349 1348/1348/1348 +f 1285/1285/1285 1273/1273/1273 1348/1348/1348 +f 1259/1259/1259 1253/1253/1253 1261/1261/1261 +f 1253/1253/1253 1251/1251/1251 1261/1261/1261 +f 1262/1262/1262 1261/1261/1261 1267/1267/1267 +f 1261/1261/1261 1251/1251/1251 1267/1267/1267 +f 1285/1285/1285 1348/1348/1348 237/237/237 +f 255/255/255 254/254/254 1286/1286/1286 +f 1352/1352/1352 1350/1350/1350 1362/1362/1362 +f 1350/1350/1350 1354/1354/1354 1362/1362/1362 +f 1285/1285/1285 1286/1286/1286 1273/1273/1273 +f 1348/1348/1348 1349/1349/1349 1283/1283/1283 +f 237/237/237 255/255/255 1286/1286/1286 +f 1286/1286/1286 1259/1259/1259 1273/1273/1273 +f 1346/1346/1346 1357/1357/1357 1363/1363/1363 +f 1364/1364/1364 682/682/682 681/681/681 +f 1365/1365/1365 1364/1364/1364 681/681/681 +f 681/681/681 685/685/685 1365/1365/1365 +f 685/685/685 702/702/702 1365/1365/1365 +f 1366/1366/1366 1364/1364/1364 1365/1365/1365 +f 1367/1367/1367 1365/1365/1365 1368/1368/1368 +f 680/680/680 682/682/682 1369/1369/1369 +f 1369/1369/1369 682/682/682 1364/1364/1364 +f 1370/1370/1370 1371/1371/1371 1372/1372/1372 +f 1367/1367/1367 1370/1370/1370 1373/1373/1373 +f 1370/1370/1370 1368/1368/1368 1374/1374/1374 +f 1375/1375/1375 1372/1372/1372 1371/1371/1371 +f 1370/1370/1370 1367/1367/1367 1368/1368/1368 +f 684/684/684 702/702/702 685/685/685 +f 1370/1370/1370 1372/1372/1372 1373/1373/1373 +f 1368/1368/1368 1365/1365/1365 702/702/702 +f 1366/1366/1366 1365/1365/1365 1367/1367/1367 +f 1376/1376/1376 1377/1377/1377 1378/1378/1378 +f 1378/1378/1378 1379/1379/1379 1380/1380/1380 +f 1381/1381/1381 1382/1382/1382 1383/1383/1383 +f 1382/1382/1382 1384/1384/1384 1383/1383/1383 +f 1385/1385/1385 1382/1382/1382 1381/1381/1381 +f 1347/1347/1347 1346/1346/1346 1363/1363/1363 +f 1384/1384/1384 1378/1378/1378 1380/1380/1380 +f 1385/1385/1385 1376/1376/1376 1378/1378/1378 +f 1369/1369/1369 1364/1364/1364 1386/1386/1386 +f 1366/1366/1366 1386/1386/1386 1364/1364/1364 +f 1373/1373/1373 1386/1386/1386 1367/1367/1367 +f 1366/1366/1366 1367/1367/1367 1386/1386/1386 +f 1379/1379/1379 396/396/396 1380/1380/1380 +f 1383/1383/1383 1384/1384/1384 397/397/397 +f 397/397/397 398/398/398 1383/1383/1383 +f 1384/1384/1384 1380/1380/1380 397/397/397 +f 1318/1318/1318 1387/1387/1387 1307/1307/1307 +f 1388/1388/1388 1307/1307/1307 1387/1387/1387 +f 1307/1307/1307 1388/1388/1388 1306/1306/1306 +f 1388/1388/1388 1389/1389/1389 1306/1306/1306 +f 1390/1390/1390 1389/1389/1389 1391/1391/1391 +f 1388/1388/1388 1391/1391/1391 1389/1389/1389 +f 1391/1391/1391 1388/1388/1388 1296/1296/1296 +f 1388/1388/1388 1387/1387/1387 1296/1296/1296 +f 1297/1297/1297 1392/1392/1392 1298/1298/1298 +f 1297/1297/1297 1393/1393/1393 1289/1289/1289 +f 1394/1394/1394 1395/1395/1395 1362/1362/1362 +f 1390/1390/1390 1298/1298/1298 1392/1392/1392 +f 1297/1297/1297 1396/1396/1396 1397/1397/1397 +f 1397/1397/1397 1396/1396/1396 1398/1398/1398 +f 1297/1297/1297 1289/1289/1289 1396/1396/1396 +f 1392/1392/1392 1297/1297/1297 1397/1397/1397 +f 1391/1391/1391 1293/1293/1293 1390/1390/1390 +f 1399/1399/1399 1359/1359/1359 1358/1358/1358 +f 1296/1296/1296 1387/1387/1387 1358/1358/1358 +f 1329/1329/1329 1359/1359/1359 1319/1319/1319 +f 1399/1399/1399 1319/1319/1319 1359/1359/1359 +f 1357/1357/1357 1346/1346/1346 1295/1295/1295 +f 1292/1292/1292 1295/1295/1295 1290/1290/1290 +f 1399/1399/1399 1358/1358/1358 1387/1387/1387 +f 1358/1358/1358 1295/1295/1295 1296/1296/1296 +f 1291/1291/1291 1279/1279/1279 1294/1294/1294 +f 1292/1292/1292 1291/1291/1291 1294/1294/1294 +f 1293/1293/1293 1298/1298/1298 1390/1390/1390 +f 1293/1293/1293 1391/1391/1391 1296/1296/1296 +f 1319/1319/1319 1399/1399/1399 1318/1318/1318 +f 1399/1399/1399 1387/1387/1387 1318/1318/1318 +f 1278/1278/1278 1393/1393/1393 1297/1297/1297 +f 1293/1293/1293 1294/1294/1294 1298/1298/1298 +f 1400/1400/1400 1394/1394/1394 1362/1362/1362 +f 1401/1401/1401 1402/1402/1402 1304/1304/1304 +f 1402/1402/1402 1344/1344/1344 1304/1304/1304 +f 1263/1263/1263 1344/1344/1344 1264/1264/1264 +f 1402/1402/1402 1264/1264/1264 1344/1344/1344 +f 1403/1403/1403 1404/1404/1404 1262/1262/1262 +f 1304/1304/1304 1305/1305/1305 1401/1401/1401 +f 1402/1402/1402 1401/1401/1401 1262/1262/1262 +f 1401/1401/1401 1403/1403/1403 1262/1262/1262 +f 1400/1400/1400 1354/1354/1354 1353/1353/1353 +f 1262/1262/1262 1404/1404/1404 1260/1260/1260 +f 1353/1353/1353 1261/1261/1261 1260/1260/1260 +f 1260/1260/1260 1400/1400/1400 1353/1353/1353 +f 1264/1264/1264 1402/1402/1402 1267/1267/1267 +f 1402/1402/1402 1262/1262/1262 1267/1267/1267 +f 1400/1400/1400 1260/1260/1260 1404/1404/1404 +f 1362/1362/1362 1354/1354/1354 1400/1400/1400 +f 1403/1403/1403 1401/1401/1401 1305/1305/1305 +f 1405/1405/1405 1406/1406/1406 1404/1404/1404 +f 1404/1404/1404 1406/1406/1406 1400/1400/1400 +f 1405/1405/1405 1392/1392/1392 1406/1406/1406 +f 1407/1407/1407 1405/1405/1405 1404/1404/1404 +f 1394/1394/1394 1406/1406/1406 1397/1397/1397 +f 1394/1394/1394 1398/1398/1398 1395/1395/1395 +f 1394/1394/1394 1400/1400/1400 1406/1406/1406 +f 1398/1398/1398 1394/1394/1394 1397/1397/1397 +f 1403/1403/1403 1407/1407/1407 1404/1404/1404 +f 1306/1306/1306 1389/1389/1389 1407/1407/1407 +f 1407/1407/1407 1403/1403/1403 1306/1306/1306 +f 1403/1403/1403 1305/1305/1305 1306/1306/1306 +f 1405/1405/1405 1389/1389/1389 1390/1390/1390 +f 1397/1397/1397 1406/1406/1406 1392/1392/1392 +f 1405/1405/1405 1407/1407/1407 1389/1389/1389 +f 1392/1392/1392 1405/1405/1405 1390/1390/1390 +f 1330/1330/1330 527/527/527 537/537/537 +f 1408/1408/1408 1409/1409/1409 1410/1410/1410 +f 1409/1409/1409 1411/1411/1411 1410/1410/1410 +f 1409/1409/1409 1408/1408/1408 1412/1412/1412 +f 1409/1409/1409 1412/1412/1412 1413/1413/1413 +f 1411/1411/1411 1414/1414/1414 1272/1272/1272 +f 1414/1414/1414 1270/1270/1270 1272/1272/1272 +f 1270/1270/1270 1415/1415/1415 1271/1271/1271 +f 1414/1414/1414 1415/1415/1415 1270/1270/1270 +f 1410/1410/1410 1411/1411/1411 1416/1416/1416 +f 1417/1417/1417 1416/1416/1416 1411/1411/1411 +f 1416/1416/1416 1417/1417/1417 1418/1418/1418 +f 1417/1417/1417 1419/1419/1419 1418/1418/1418 +f 1250/1250/1250 1419/1419/1419 1274/1274/1274 +f 1417/1417/1417 1274/1274/1274 1419/1419/1419 +f 1272/1272/1272 1274/1274/1274 1411/1411/1411 +f 1417/1417/1417 1411/1411/1411 1274/1274/1274 +f 1420/1420/1420 1413/1413/1413 1421/1421/1421 +f 1422/1422/1422 1341/1341/1341 1342/1342/1342 +f 1423/1423/1423 1424/1424/1424 1340/1340/1340 +f 1425/1425/1425 1426/1426/1426 1427/1427/1427 +f 1342/1342/1342 1426/1426/1426 1428/1428/1428 +f 1341/1341/1341 1422/1422/1422 1340/1340/1340 +f 1341/1341/1341 1340/1340/1340 1335/1335/1335 +f 1422/1422/1422 1423/1423/1423 1340/1340/1340 +f 1429/1429/1429 1422/1422/1422 1342/1342/1342 +f 1420/1420/1420 1415/1415/1415 1413/1413/1413 +f 1415/1415/1415 1414/1414/1414 1413/1413/1413 +f 1420/1420/1420 1421/1421/1421 1427/1427/1427 +f 1420/1420/1420 1271/1271/1271 1415/1415/1415 +f 1420/1420/1420 1427/1427/1427 1426/1426/1426 +f 1426/1426/1426 1271/1271/1271 1420/1420/1420 +f 1426/1426/1426 1342/1342/1342 1336/1336/1336 +f 1271/1271/1271 1426/1426/1426 1336/1336/1336 +f 1430/1430/1430 1416/1416/1416 1418/1418/1418 +f 1275/1275/1275 284/284/284 1431/1431/1431 +f 1432/1432/1432 1433/1433/1433 1434/1434/1434 +f 1431/1431/1431 284/284/284 1435/1435/1435 +f 1301/1301/1301 1275/1275/1275 1431/1431/1431 +f 1436/1436/1436 1437/1437/1437 1438/1438/1438 +f 1439/1439/1439 1440/1440/1440 1435/1435/1435 +f 1440/1440/1440 1432/1432/1432 1434/1434/1434 +f 1438/1438/1438 1437/1437/1437 1440/1440/1440 +f 1153/1153/1153 1441/1441/1441 468/468/468 +f 1432/1432/1432 1440/1440/1440 1439/1439/1439 +f 1442/1442/1442 469/469/469 470/470/470 +f 1441/1441/1441 1435/1435/1435 468/468/468 +f 1443/1443/1443 1431/1431/1431 1440/1440/1440 +f 1435/1435/1435 284/284/284 468/468/468 +f 1435/1435/1435 1441/1441/1441 1439/1439/1439 +f 1440/1440/1440 1431/1431/1431 1435/1435/1435 +f 1443/1443/1443 1440/1440/1440 1437/1437/1437 +f 1244/1244/1244 1436/1436/1436 1250/1250/1250 +f 1436/1436/1436 1419/1419/1419 1250/1250/1250 +f 1419/1419/1419 1436/1436/1436 1418/1418/1418 +f 1436/1436/1436 1438/1438/1438 1418/1418/1418 +f 1416/1416/1416 1430/1430/1430 1410/1410/1410 +f 1430/1430/1430 1408/1408/1408 1410/1410/1410 +f 1249/1249/1249 1437/1437/1437 1244/1244/1244 +f 1436/1436/1436 1244/1244/1244 1437/1437/1437 +f 1301/1301/1301 1431/1431/1431 1300/1300/1300 +f 1443/1443/1443 1300/1300/1300 1431/1431/1431 +f 1300/1300/1300 1443/1443/1443 1249/1249/1249 +f 1443/1443/1443 1437/1437/1437 1249/1249/1249 +f 1434/1434/1434 1438/1438/1438 1440/1440/1440 +f 1433/1433/1433 1438/1438/1438 1434/1434/1434 +f 1433/1433/1433 1430/1430/1430 1418/1418/1418 +f 1433/1433/1433 1418/1418/1418 1438/1438/1438 +f 1325/1325/1325 1444/1444/1444 528/528/528 +f 1444/1444/1444 1159/1159/1159 528/528/528 +f 1444/1444/1444 1445/1445/1445 1159/1159/1159 +f 1159/1159/1159 1445/1445/1445 1157/1157/1157 +f 1095/1095/1095 1446/1446/1446 1164/1164/1164 +f 1447/1447/1447 1164/1164/1164 1446/1446/1446 +f 1308/1308/1308 1448/1448/1448 1325/1325/1325 +f 1444/1444/1444 1325/1325/1325 1448/1448/1448 +f 1445/1445/1445 1449/1449/1449 1157/1157/1157 +f 1449/1449/1449 1156/1156/1156 1157/1157/1157 +f 940/940/940 1156/1156/1156 1450/1450/1450 +f 1449/1449/1449 1450/1450/1450 1156/1156/1156 +f 1445/1445/1445 1444/1444/1444 1451/1451/1451 +f 1444/1444/1444 1448/1448/1448 1451/1451/1451 +f 1451/1451/1451 1452/1452/1452 1445/1445/1445 +f 1449/1449/1449 1445/1445/1445 1452/1452/1452 +f 1164/1164/1164 1447/1447/1447 452/452/452 +f 1453/1453/1453 1454/1454/1454 1455/1455/1455 +f 1086/1086/1086 1446/1446/1446 1095/1095/1095 +f 1456/1456/1456 1457/1457/1457 1454/1454/1454 +f 1458/1458/1458 1455/1455/1455 1454/1454/1454 +f 1447/1447/1447 1446/1446/1446 1455/1455/1455 +f 1459/1459/1459 1455/1455/1455 1460/1460/1460 +f 1461/1461/1461 1462/1462/1462 1460/1460/1460 +f 1446/1446/1446 1460/1460/1460 1455/1455/1455 +f 1447/1447/1447 1463/1463/1463 452/452/452 +f 1459/1459/1459 1453/1453/1453 1455/1455/1455 +f 1458/1458/1458 1463/1463/1463 1455/1455/1455 +f 1447/1447/1447 1455/1455/1455 1463/1463/1463 +f 1453/1453/1453 1464/1464/1464 1454/1454/1454 +f 1464/1464/1464 1456/1456/1456 1454/1454/1454 +f 1465/1465/1465 1464/1464/1464 1459/1459/1459 +f 1464/1464/1464 1453/1453/1453 1459/1459/1459 +f 1466/1466/1466 1310/1310/1310 1467/1467/1467 +f 1467/1467/1467 1468/1468/1468 1469/1469/1469 +f 1468/1468/1468 1470/1470/1470 1469/1469/1469 +f 1471/1471/1471 1470/1470/1470 1472/1472/1472 +f 1473/1473/1473 1472/1472/1472 1468/1468/1468 +f 1474/1474/1474 1475/1475/1475 1476/1476/1476 +f 1477/1477/1477 1478/1478/1478 1476/1476/1476 +f 1473/1473/1473 1468/1468/1468 1312/1312/1312 +f 1468/1468/1468 1467/1467/1467 1312/1312/1312 +f 1339/1339/1339 1473/1473/1473 1312/1312/1312 +f 1340/1340/1340 1337/1337/1337 1335/1335/1335 +f 1472/1472/1472 1473/1473/1473 1424/1424/1424 +f 1473/1473/1473 1340/1340/1340 1424/1424/1424 +f 1472/1472/1472 1479/1479/1479 1471/1471/1471 +f 1472/1472/1472 1470/1470/1470 1468/1468/1468 +f 1473/1473/1473 1339/1339/1339 1340/1340/1340 +f 1478/1478/1478 1477/1477/1477 1471/1471/1471 +f 1476/1476/1476 1480/1480/1480 1477/1477/1477 +f 1466/1466/1466 1467/1467/1467 1469/1469/1469 +f 1451/1451/1451 1448/1448/1448 1481/1481/1481 +f 1452/1452/1452 1481/1481/1481 1482/1482/1482 +f 1481/1481/1481 1466/1466/1466 1469/1469/1469 +f 1466/1466/1466 1448/1448/1448 1308/1308/1308 +f 1312/1312/1312 1467/1467/1467 1310/1310/1310 +f 1466/1466/1466 1481/1481/1481 1448/1448/1448 +f 1310/1310/1310 1466/1466/1466 1308/1308/1308 +f 1477/1477/1477 1480/1480/1480 1469/1469/1469 +f 1470/1470/1470 1477/1477/1477 1469/1469/1469 +f 1477/1477/1477 1470/1470/1470 1471/1471/1471 +f 1483/1483/1483 1469/1469/1469 1480/1480/1480 +f 1481/1481/1481 1469/1469/1469 1482/1482/1482 +f 1451/1451/1451 1481/1481/1481 1452/1452/1452 +f 1482/1482/1482 1469/1469/1469 1483/1483/1483 +f 1484/1484/1484 1449/1449/1449 1452/1452/1452 +f 1485/1485/1485 1486/1486/1486 465/465/465 +f 1487/1487/1487 1488/1488/1488 1347/1347/1347 +f 1363/1363/1363 1487/1487/1487 1347/1347/1347 +f 1489/1489/1489 1490/1490/1490 1457/1457/1457 +f 1457/1457/1457 1280/1280/1280 1488/1488/1488 +f 1281/1281/1281 1280/1280/1280 1490/1490/1490 +f 1488/1488/1488 1280/1280/1280 1291/1291/1291 +f 1487/1487/1487 1457/1457/1457 1488/1488/1488 +f 1490/1490/1490 1280/1280/1280 1457/1457/1457 +f 1463/1463/1463 1491/1491/1491 452/452/452 +f 1458/1458/1458 1492/1492/1492 1463/1463/1463 +f 1493/1493/1493 1487/1487/1487 1363/1363/1363 +f 443/443/443 452/452/452 1491/1491/1491 +f 1487/1487/1487 1492/1492/1492 1458/1458/1458 +f 1487/1487/1487 1454/1454/1454 1457/1457/1457 +f 1491/1491/1491 1463/1463/1463 1492/1492/1492 +f 1454/1454/1454 1487/1487/1487 1458/1458/1458 +f 1488/1488/1488 1291/1291/1291 1290/1290/1290 +f 1494/1494/1494 1281/1281/1281 1495/1495/1495 +f 1496/1496/1496 1282/1282/1282 1281/1281/1281 +f 1497/1497/1497 1282/1282/1282 1496/1496/1496 +f 1495/1495/1495 1281/1281/1281 1490/1490/1490 +f 1287/1287/1287 1393/1393/1393 1497/1497/1497 +f 1287/1287/1287 1498/1498/1498 1288/1288/1288 +f 1282/1282/1282 1497/1497/1497 1393/1393/1393 +f 1499/1499/1499 1287/1287/1287 1497/1497/1497 +f 1456/1456/1456 1489/1489/1489 1457/1457/1457 +f 1489/1489/1489 1495/1495/1495 1490/1490/1490 +f 1347/1347/1347 1488/1488/1488 1290/1290/1290 +f 1500/1500/1500 1489/1489/1489 1456/1456/1456 +f 1501/1501/1501 1496/1496/1496 1494/1494/1494 +f 1502/1502/1502 1499/1499/1499 1497/1497/1497 +f 1500/1500/1500 1495/1495/1495 1489/1489/1489 +f 1496/1496/1496 1281/1281/1281 1494/1494/1494 +f 1503/1503/1503 1493/1493/1493 1363/1363/1363 +f 535/535/535 448/448/448 1504/1504/1504 +f 1505/1505/1505 1504/1504/1504 448/448/448 +f 1328/1328/1328 1327/1327/1327 1504/1504/1504 +f 1506/1506/1506 1504/1504/1504 1327/1327/1327 +f 1504/1504/1504 1505/1505/1505 1328/1328/1328 +f 1505/1505/1505 1507/1507/1507 1328/1328/1328 +f 1507/1507/1507 1505/1505/1505 448/448/448 +f 1329/1329/1329 1360/1360/1360 1359/1359/1359 +f 1330/1330/1330 1506/1506/1506 1321/1321/1321 +f 1506/1506/1506 1327/1327/1327 1321/1321/1321 +f 1321/1321/1321 1309/1309/1309 1330/1330/1330 +f 1326/1326/1326 1330/1330/1330 1309/1309/1309 +f 1504/1504/1504 1506/1506/1506 535/535/535 +f 1506/1506/1506 533/533/533 535/535/535 +f 537/537/537 533/533/533 1330/1330/1330 +f 1506/1506/1506 1330/1330/1330 533/533/533 +f 1328/1328/1328 1507/1507/1507 1323/1323/1323 +f 1492/1492/1492 1508/1508/1508 1491/1491/1491 +f 1509/1509/1509 1491/1491/1491 1503/1503/1503 +f 1356/1356/1356 1503/1503/1503 1357/1357/1357 +f 1491/1491/1491 1509/1509/1509 443/443/443 +f 1487/1487/1487 1493/1493/1493 1492/1492/1492 +f 1493/1493/1493 1508/1508/1508 1492/1492/1492 +f 1491/1491/1491 1508/1508/1508 1503/1503/1503 +f 1493/1493/1493 1503/1503/1503 1508/1508/1508 +f 1509/1509/1509 1507/1507/1507 443/443/443 +f 1503/1503/1503 1356/1356/1356 1509/1509/1509 +f 1507/1507/1507 1329/1329/1329 1323/1323/1323 +f 448/448/448 443/443/443 1507/1507/1507 +f 1356/1356/1356 1360/1360/1360 1509/1509/1509 +f 1363/1363/1363 1357/1357/1357 1503/1503/1503 +f 1507/1507/1507 1360/1360/1360 1329/1329/1329 +f 1509/1509/1509 1360/1360/1360 1507/1507/1507 +f 1510/1510/1510 1511/1511/1511 1512/1512/1512 +f 1510/1510/1510 1513/1513/1513 1511/1511/1511 +f 1514/1514/1514 1515/1515/1515 1516/1516/1516 +f 1511/1511/1511 1513/1513/1513 1517/1517/1517 +f 1513/1513/1513 1518/1518/1518 1519/1519/1519 +f 1510/1510/1510 1512/1512/1512 1520/1520/1520 +f 1512/1512/1512 1511/1511/1511 1521/1521/1521 +f 1522/1522/1522 1512/1512/1512 1521/1521/1521 +f 1523/1523/1523 1524/1524/1524 1516/1516/1516 +f 1524/1524/1524 1525/1525/1525 1516/1516/1516 +f 1514/1514/1514 1516/1516/1516 1526/1526/1526 +f 1516/1516/1516 1525/1525/1525 1526/1526/1526 +f 1517/1517/1517 1527/1527/1527 1528/1528/1528 +f 1529/1529/1529 1515/1515/1515 1514/1514/1514 +f 1486/1486/1486 1530/1530/1530 1523/1523/1523 +f 1515/1515/1515 1523/1523/1523 1516/1516/1516 +f 1518/1518/1518 1513/1513/1513 1510/1510/1510 +f 1531/1531/1531 363/363/363 1529/1529/1529 +f 1532/1532/1532 471/471/471 1531/1531/1531 +f 1532/1532/1532 1519/1519/1519 471/471/471 +f 1531/1531/1531 471/471/471 363/363/363 +f 1515/1515/1515 363/363/363 1533/1533/1533 +f 362/362/362 465/465/465 1486/1486/1486 +f 1529/1529/1529 363/363/363 1515/1515/1515 +f 1533/1533/1533 362/362/362 1486/1486/1486 +f 1520/1520/1520 1512/1512/1512 1534/1534/1534 +f 1535/1535/1535 1518/1518/1518 1536/1536/1536 +f 1512/1512/1512 1522/1522/1522 1534/1534/1534 +f 1534/1534/1534 1537/1537/1537 1520/1520/1520 +f 470/470/470 1519/1519/1519 1442/1442/1442 +f 471/471/471 1519/1519/1519 470/470/470 +f 1442/1442/1442 1518/1518/1518 1535/1535/1535 +f 1442/1442/1442 1535/1535/1535 469/469/469 +f 1538/1538/1538 1539/1539/1539 1540/1540/1540 +f 1541/1541/1541 1542/1542/1542 1543/1543/1543 +f 1544/1544/1544 1543/1543/1543 1545/1545/1545 +f 1544/1544/1544 1546/1546/1546 1498/1498/1498 +f 1547/1547/1547 1546/1546/1546 1544/1544/1544 +f 1548/1548/1548 1546/1546/1546 1547/1547/1547 +f 1549/1549/1549 1550/1550/1550 1551/1551/1551 +f 1552/1552/1552 1544/1544/1544 1545/1545/1545 +f 1552/1552/1552 1547/1547/1547 1544/1544/1544 +f 1543/1543/1543 1498/1498/1498 1499/1499/1499 +f 1541/1541/1541 1543/1543/1543 1499/1499/1499 +f 1498/1498/1498 1287/1287/1287 1499/1499/1499 +f 1393/1393/1393 1278/1278/1278 1282/1282/1282 +f 1393/1393/1393 1287/1287/1287 1289/1289/1289 +f 1543/1543/1543 1544/1544/1544 1498/1498/1498 +f 1498/1498/1498 1546/1546/1546 1288/1288/1288 +f 1288/1288/1288 1546/1546/1546 1553/1553/1553 +f 1548/1548/1548 1547/1547/1547 1551/1551/1551 +f 1554/1554/1554 1523/1523/1523 1555/1555/1555 +f 1523/1523/1523 1530/1530/1530 1556/1556/1556 +f 1555/1555/1555 1523/1523/1523 1556/1556/1556 +f 1555/1555/1555 1556/1556/1556 1549/1549/1549 +f 1540/1540/1540 1539/1539/1539 1485/1485/1485 +f 1485/1485/1485 1539/1539/1539 1557/1557/1557 +f 1556/1556/1556 1557/1557/1557 1539/1539/1539 +f 1554/1554/1554 1555/1555/1555 1549/1549/1549 +f 1549/1549/1549 1558/1558/1558 1554/1554/1554 +f 1556/1556/1556 1539/1539/1539 1550/1550/1550 +f 1550/1550/1550 1539/1539/1539 1548/1548/1548 +f 1525/1525/1525 1554/1554/1554 1558/1558/1558 +f 1554/1554/1554 1525/1525/1525 1524/1524/1524 +f 1524/1524/1524 1523/1523/1523 1554/1554/1554 +f 1549/1549/1549 1556/1556/1556 1550/1550/1550 +f 1550/1550/1550 1548/1548/1548 1551/1551/1551 +f 1371/1371/1371 1370/1370/1370 1374/1374/1374 +f 1559/1559/1559 1560/1560/1560 1561/1561/1561 +f 1562/1562/1562 1560/1560/1560 1559/1559/1559 +f 1563/1563/1563 1564/1564/1564 1565/1565/1565 +f 1561/1561/1561 1560/1560/1560 1564/1564/1564 +f 1566/1566/1566 1567/1567/1567 1568/1568/1568 +f 1568/1568/1568 1563/1563/1563 1569/1569/1569 +f 1570/1570/1570 1571/1571/1571 1572/1572/1572 +f 1569/1569/1569 1566/1566/1566 1568/1568/1568 +f 1564/1564/1564 1563/1563/1563 1568/1568/1568 +f 1564/1564/1564 1560/1560/1560 1565/1565/1565 +f 1573/1573/1573 1574/1574/1574 1575/1575/1575 +f 1573/1573/1573 1575/1575/1575 1576/1576/1576 +f 1568/1568/1568 1567/1567/1567 1564/1564/1564 +f 1561/1561/1561 1564/1564/1564 1567/1567/1567 +f 1577/1577/1577 1560/1560/1560 1571/1571/1571 +f 1565/1565/1565 1560/1560/1560 1577/1577/1577 +f 1563/1563/1563 1578/1578/1578 1569/1569/1569 +f 1579/1579/1579 1580/1580/1580 1581/1581/1581 +f 1580/1580/1580 1582/1582/1582 1583/1583/1583 +f 1584/1584/1584 1585/1585/1585 1586/1586/1586 +f 1581/1581/1581 1584/1584/1584 1586/1586/1586 +f 1587/1587/1587 1588/1588/1588 1586/1586/1586 +f 1586/1586/1586 1588/1588/1588 1581/1581/1581 +f 1589/1589/1589 1586/1586/1586 1590/1590/1590 +f 1362/1362/1362 1589/1589/1589 1590/1590/1590 +f 1591/1591/1591 1592/1592/1592 1593/1593/1593 +f 1594/1594/1594 1595/1595/1595 1591/1591/1591 +f 1578/1578/1578 1596/1596/1596 1569/1569/1569 +f 1593/1593/1593 1592/1592/1592 1597/1597/1597 +f 1598/1598/1598 1595/1595/1595 1594/1594/1594 +f 1586/1586/1586 1585/1585/1585 1590/1590/1590 +f 1599/1599/1599 1580/1580/1580 1598/1598/1598 +f 1599/1599/1599 1598/1598/1598 1594/1594/1594 +f 1570/1570/1570 1575/1575/1575 1571/1571/1571 +f 1600/1600/1600 1601/1601/1601 1602/1602/1602 +f 1600/1600/1600 1602/1602/1602 1603/1603/1603 +f 1600/1600/1600 1574/1574/1574 1604/1604/1604 +f 1605/1605/1605 1602/1602/1602 1601/1601/1601 +f 1606/1606/1606 1607/1607/1607 1601/1601/1601 +f 1601/1601/1601 1600/1600/1600 1604/1604/1604 +f 1574/1574/1574 1573/1573/1573 1604/1604/1604 +f 1573/1573/1573 1606/1606/1606 1601/1601/1601 +f 1608/1608/1608 1609/1609/1609 1501/1501/1501 +f 1608/1608/1608 1494/1494/1494 1495/1495/1495 +f 1608/1608/1608 1610/1610/1610 1609/1609/1609 +f 1494/1494/1494 1608/1608/1608 1501/1501/1501 +f 1605/1605/1605 1465/1465/1465 1611/1611/1611 +f 1605/1605/1605 1612/1612/1612 1602/1602/1602 +f 1610/1610/1610 1608/1608/1608 1500/1500/1500 +f 1612/1612/1612 1605/1605/1605 1611/1611/1611 +f 1604/1604/1604 1573/1573/1573 1601/1601/1601 +f 1613/1613/1613 1614/1614/1614 1615/1615/1615 +f 1614/1614/1614 1574/1574/1574 1615/1615/1615 +f 1571/1571/1571 1613/1613/1613 1616/1616/1616 +f 1577/1577/1577 1571/1571/1571 1616/1616/1616 +f 1571/1571/1571 1574/1574/1574 1614/1614/1614 +f 1575/1575/1575 1574/1574/1574 1571/1571/1571 +f 1614/1614/1614 1613/1613/1613 1571/1571/1571 +f 1615/1615/1615 1574/1574/1574 1600/1600/1600 +f 1609/1609/1609 1617/1617/1617 1607/1607/1607 +f 1606/1606/1606 1609/1609/1609 1607/1607/1607 +f 1618/1618/1618 1606/1606/1606 1573/1573/1573 +f 1618/1618/1618 1619/1619/1619 1606/1606/1606 +f 1560/1560/1560 1572/1572/1572 1571/1571/1571 +f 1562/1562/1562 1572/1572/1572 1560/1560/1560 +f 1501/1501/1501 1609/1609/1609 1619/1619/1619 +f 1619/1619/1619 1609/1609/1609 1606/1606/1606 +f 1620/1620/1620 1621/1621/1621 1579/1579/1579 +f 1595/1595/1595 1598/1598/1598 1621/1621/1621 +f 1597/1597/1597 1580/1580/1580 1599/1599/1599 +f 1597/1597/1597 1599/1599/1599 1593/1593/1593 +f 1595/1595/1595 1621/1621/1621 1622/1622/1622 +f 1622/1622/1622 1621/1621/1621 1620/1620/1620 +f 1621/1621/1621 1598/1598/1598 1580/1580/1580 +f 1579/1579/1579 1621/1621/1621 1580/1580/1580 +f 1623/1623/1623 1592/1592/1592 1624/1624/1624 +f 1625/1625/1625 1624/1624/1624 1626/1626/1626 +f 1626/1626/1626 1627/1627/1627 1625/1625/1625 +f 1623/1623/1623 1624/1624/1624 1628/1628/1628 +f 1592/1592/1592 1623/1623/1623 1597/1597/1597 +f 1628/1628/1628 1629/1629/1629 1597/1597/1597 +f 1624/1624/1624 1592/1592/1592 1626/1626/1626 +f 1623/1623/1623 1628/1628/1628 1597/1597/1597 +f 1630/1630/1630 1620/1620/1620 1579/1579/1579 +f 1631/1631/1631 1632/1632/1632 1633/1633/1633 +f 1634/1634/1634 1632/1632/1632 1635/1635/1635 +f 1635/1635/1635 1632/1632/1632 1631/1631/1631 +f 1631/1631/1631 1622/1622/1622 1635/1635/1635 +f 1636/1636/1636 1633/1633/1633 1637/1637/1637 +f 1636/1636/1636 1637/1637/1637 1625/1625/1625 +f 1632/1632/1632 1637/1637/1637 1633/1633/1633 +f 1634/1634/1634 1637/1637/1637 1632/1632/1632 +f 1638/1638/1638 1639/1639/1639 1640/1640/1640 +f 1639/1639/1639 1630/1630/1630 1640/1640/1640 +f 1639/1639/1639 1620/1620/1620 1630/1630/1630 +f 1640/1640/1640 1630/1630/1630 1581/1581/1581 +f 1622/1622/1622 1620/1620/1620 1639/1639/1639 +f 1641/1641/1641 1635/1635/1635 1639/1639/1639 +f 1635/1635/1635 1622/1622/1622 1639/1639/1639 +f 1642/1642/1642 1639/1639/1639 1638/1638/1638 +f 1627/1627/1627 1636/1636/1636 1625/1625/1625 +f 1643/1643/1643 1642/1642/1642 1644/1644/1644 +f 1645/1645/1645 1396/1396/1396 1289/1289/1289 +f 1587/1587/1587 1589/1589/1589 1395/1395/1395 +f 1398/1398/1398 1644/1644/1644 1646/1646/1646 +f 1642/1642/1642 1643/1643/1643 1641/1641/1641 +f 1641/1641/1641 1643/1643/1643 1647/1647/1647 +f 1648/1648/1648 1643/1643/1643 1289/1289/1289 +f 1643/1643/1643 1644/1644/1644 1645/1645/1645 +f 1640/1640/1640 1588/1588/1588 1646/1646/1646 +f 1644/1644/1644 1638/1638/1638 1646/1646/1646 +f 1630/1630/1630 1579/1579/1579 1581/1581/1581 +f 1588/1588/1588 1640/1640/1640 1581/1581/1581 +f 1589/1589/1589 1587/1587/1587 1586/1586/1586 +f 1362/1362/1362 1395/1395/1395 1589/1589/1589 +f 1640/1640/1640 1646/1646/1646 1638/1638/1638 +f 1587/1587/1587 1646/1646/1646 1588/1588/1588 +f 1642/1642/1642 1638/1638/1638 1644/1644/1644 +f 1591/1591/1591 1627/1627/1627 1626/1626/1626 +f 1592/1592/1592 1591/1591/1591 1626/1626/1626 +f 1649/1649/1649 1622/1622/1622 1631/1631/1631 +f 1631/1631/1631 1633/1633/1633 1649/1649/1649 +f 1627/1627/1627 1649/1649/1649 1636/1636/1636 +f 1637/1637/1637 1624/1624/1624 1625/1625/1625 +f 1649/1649/1649 1627/1627/1627 1591/1591/1591 +f 1633/1633/1633 1636/1636/1636 1649/1649/1649 +f 1538/1538/1538 1650/1650/1650 1651/1651/1651 +f 1651/1651/1651 1652/1652/1652 1553/1553/1553 +f 1641/1641/1641 1639/1639/1639 1642/1642/1642 +f 1652/1652/1652 1647/1647/1647 1553/1553/1553 +f 1595/1595/1595 1622/1622/1622 1591/1591/1591 +f 1649/1649/1649 1591/1591/1591 1622/1622/1622 +f 1599/1599/1599 1594/1594/1594 1593/1593/1593 +f 1591/1591/1591 1593/1593/1593 1594/1594/1594 +f 1617/1617/1617 1609/1609/1609 1610/1610/1610 +f 1653/1653/1653 1654/1654/1654 1655/1655/1655 +f 1656/1656/1656 1654/1654/1654 1653/1653/1653 +f 1657/1657/1657 1658/1658/1658 1659/1659/1659 +f 1653/1653/1653 1655/1655/1655 1660/1660/1660 +f 1660/1660/1660 1658/1658/1658 1657/1657/1657 +f 1661/1661/1661 1658/1658/1658 1660/1660/1660 +f 1662/1662/1662 1658/1658/1658 1661/1661/1661 +f 1657/1657/1657 1656/1656/1656 1653/1653/1653 +f 1663/1663/1663 1664/1664/1664 1655/1655/1655 +f 1663/1663/1663 1665/1665/1665 1666/1666/1666 +f 1667/1667/1667 1668/1668/1668 1669/1669/1669 +f 1663/1663/1663 1655/1655/1655 1670/1670/1670 +f 1661/1661/1661 246/246/246 1662/1662/1662 +f 1658/1658/1658 1662/1662/1662 712/712/712 +f 1666/1666/1666 1664/1664/1664 1663/1663/1663 +f 246/246/246 712/712/712 1662/1662/1662 +f 1671/1671/1671 1657/1657/1657 1659/1659/1659 +f 1672/1672/1672 1673/1673/1673 1674/1674/1674 +f 1675/1675/1675 1676/1676/1676 1672/1672/1672 +f 591/591/591 1677/1677/1677 1659/1659/1659 +f 1673/1673/1673 1671/1671/1671 1677/1677/1677 +f 1656/1656/1656 1671/1671/1671 1673/1673/1673 +f 1678/1678/1678 1654/1654/1654 1656/1656/1656 +f 1673/1673/1673 1672/1672/1672 1676/1676/1676 +f 1676/1676/1676 1678/1678/1678 1673/1673/1673 +f 591/591/591 1658/1658/1658 711/711/711 +f 1659/1659/1659 1658/1658/1658 591/591/591 +f 1656/1656/1656 1657/1657/1657 1671/1671/1671 +f 711/711/711 1658/1658/1658 712/712/712 +f 1677/1677/1677 1679/1679/1679 1674/1674/1674 +f 1671/1671/1671 1659/1659/1659 1677/1677/1677 +f 1677/1677/1677 591/591/591 1679/1679/1679 +f 1673/1673/1673 1677/1677/1677 1674/1674/1674 +f 1666/1666/1666 1669/1669/1669 1680/1680/1680 +f 689/689/689 1681/1681/1681 1682/1682/1682 +f 692/692/692 689/689/689 1682/1682/1682 +f 1683/1683/1683 1684/1684/1684 1685/1685/1685 +f 1683/1683/1683 1685/1685/1685 1686/1686/1686 +f 1687/1687/1687 1688/1688/1688 1683/1683/1683 +f 1689/1689/1689 1687/1687/1687 1683/1683/1683 +f 1690/1690/1690 1682/1682/1682 1681/1681/1681 +f 1681/1681/1681 1691/1691/1691 1690/1690/1690 +f 1692/1692/1692 1693/1693/1693 650/650/650 +f 646/646/646 1694/1694/1694 647/647/647 +f 1413/1413/1413 1414/1414/1414 1409/1409/1409 +f 1409/1409/1409 1414/1414/1414 1411/1411/1411 +f 650/650/650 1693/1693/1693 671/671/671 +f 1693/1693/1693 1695/1695/1695 671/671/671 +f 1696/1696/1696 672/672/672 1695/1695/1695 +f 672/672/672 671/671/671 1695/1695/1695 +f 1681/1681/1681 1697/1697/1697 1691/1691/1691 +f 1654/1654/1654 1678/1678/1678 1655/1655/1655 +f 1653/1653/1653 1660/1660/1660 1657/1657/1657 +f 1669/1669/1669 1698/1698/1698 1699/1699/1699 +f 1655/1655/1655 1678/1678/1678 1670/1670/1670 +f 1669/1669/1669 1699/1699/1699 1680/1680/1680 +f 1665/1665/1665 1667/1667/1667 1669/1669/1669 +f 1664/1664/1664 1680/1680/1680 1700/1700/1700 +f 1680/1680/1680 1664/1664/1664 1666/1666/1666 +f 1701/1701/1701 1702/1702/1702 1703/1703/1703 +f 1704/1704/1704 1705/1705/1705 1706/1706/1706 +f 1697/1697/1697 1707/1707/1707 1691/1691/1691 +f 1702/1702/1702 1708/1708/1708 1703/1703/1703 +f 1698/1698/1698 1705/1705/1705 1704/1704/1704 +f 1680/1680/1680 1699/1699/1699 1700/1700/1700 +f 1699/1699/1699 1698/1698/1698 1704/1704/1704 +f 1700/1700/1700 1699/1699/1699 1704/1704/1704 +f 1383/1383/1383 398/398/398 1578/1578/1578 +f 1383/1383/1383 1578/1578/1578 1563/1563/1563 +f 398/398/398 247/247/247 1596/1596/1596 +f 398/398/398 1596/1596/1596 1578/1578/1578 +f 1381/1381/1381 1563/1563/1563 1565/1565/1565 +f 1376/1376/1376 1385/1385/1385 1565/1565/1565 +f 1381/1381/1381 1383/1383/1383 1563/1563/1563 +f 1385/1385/1385 1381/1381/1381 1565/1565/1565 +f 588/588/588 1709/1709/1709 1674/1674/1674 +f 591/591/591 588/588/588 1679/1679/1679 +f 1702/1702/1702 1710/1710/1710 1711/1711/1711 +f 1679/1679/1679 588/588/588 1674/1674/1674 +f 1708/1708/1708 1709/1709/1709 587/587/587 +f 1708/1708/1708 587/587/587 589/589/589 +f 588/588/588 587/587/587 1709/1709/1709 +f 1709/1709/1709 1711/1711/1711 1672/1672/1672 +f 1376/1376/1376 1565/1565/1565 1577/1577/1577 +f 1612/1612/1612 1603/1603/1603 1602/1602/1602 +f 1465/1465/1465 1617/1617/1617 1464/1464/1464 +f 1607/1607/1607 1605/1605/1605 1601/1601/1601 +f 1607/1607/1607 1465/1465/1465 1605/1605/1605 +f 1608/1608/1608 1495/1495/1495 1500/1500/1500 +f 1456/1456/1456 1610/1610/1610 1500/1500/1500 +f 1456/1456/1456 1464/1464/1464 1617/1617/1617 +f 1456/1456/1456 1617/1617/1617 1610/1610/1610 +f 1712/1712/1712 1616/1616/1616 1613/1613/1613 +f 1712/1712/1712 1613/1613/1613 1713/1713/1713 +f 1376/1376/1376 1577/1577/1577 1616/1616/1616 +f 1376/1376/1376 1616/1616/1616 1712/1712/1712 +f 1603/1603/1603 1615/1615/1615 1600/1600/1600 +f 1617/1617/1617 1465/1465/1465 1607/1607/1607 +f 1713/1713/1713 1613/1613/1613 1615/1615/1615 +f 1603/1603/1603 1713/1713/1713 1615/1615/1615 +f 1708/1708/1708 1702/1702/1702 1711/1711/1711 +f 1665/1665/1665 1670/1670/1670 1714/1714/1714 +f 1667/1667/1667 1665/1665/1665 1714/1714/1714 +f 1666/1666/1666 1665/1665/1665 1669/1669/1669 +f 1714/1714/1714 1670/1670/1670 1715/1715/1715 +f 1716/1716/1716 1717/1717/1717 1668/1668/1668 +f 1718/1718/1718 1668/1668/1668 1717/1717/1717 +f 1665/1665/1665 1663/1663/1663 1670/1670/1670 +f 1711/1711/1711 1717/1717/1717 1716/1716/1716 +f 1715/1715/1715 1670/1670/1670 1678/1678/1678 +f 1676/1676/1676 1714/1714/1714 1715/1715/1715 +f 1716/1716/1716 1676/1676/1676 1675/1675/1675 +f 1676/1676/1676 1716/1716/1716 1714/1714/1714 +f 1668/1668/1668 1667/1667/1667 1716/1716/1716 +f 1667/1667/1667 1714/1714/1714 1716/1716/1716 +f 1678/1678/1678 1656/1656/1656 1673/1673/1673 +f 1715/1715/1715 1678/1678/1678 1676/1676/1676 +f 1705/1705/1705 1698/1698/1698 1719/1719/1719 +f 1701/1701/1701 1706/1706/1706 1720/1720/1720 +f 1711/1711/1711 1716/1716/1716 1675/1675/1675 +f 1720/1720/1720 1705/1705/1705 1719/1719/1719 +f 1706/1706/1706 1705/1705/1705 1720/1720/1720 +f 1709/1709/1709 1708/1708/1708 1711/1711/1711 +f 1710/1710/1710 1717/1717/1717 1711/1711/1711 +f 1674/1674/1674 1709/1709/1709 1672/1672/1672 +f 1672/1672/1672 1711/1711/1711 1675/1675/1675 +f 1718/1718/1718 1698/1698/1698 1669/1669/1669 +f 1720/1720/1720 1719/1719/1719 1717/1717/1717 +f 1718/1718/1718 1719/1719/1719 1698/1698/1698 +f 1668/1668/1668 1718/1718/1718 1669/1669/1669 +f 1701/1701/1701 1720/1720/1720 1702/1702/1702 +f 1719/1719/1719 1718/1718/1718 1717/1717/1717 +f 1702/1702/1702 1720/1720/1720 1710/1710/1710 +f 1710/1710/1710 1720/1720/1720 1717/1717/1717 +f 1721/1721/1721 1628/1628/1628 1722/1722/1722 +f 1723/1723/1723 1724/1724/1724 1725/1725/1725 +f 1726/1726/1726 1725/1725/1725 1724/1724/1724 +f 1727/1727/1727 1728/1728/1728 1724/1724/1724 +f 1729/1729/1729 1724/1724/1724 1728/1728/1728 +f 1725/1725/1725 1726/1726/1726 1730/1730/1730 +f 1731/1731/1731 1730/1730/1730 1726/1726/1726 +f 1724/1724/1724 1729/1729/1729 1726/1726/1726 +f 1732/1732/1732 1726/1726/1726 1729/1729/1729 +f 1733/1733/1733 1734/1734/1734 1735/1735/1735 +f 1728/1728/1728 1734/1734/1734 1736/1736/1736 +f 1737/1737/1737 1738/1738/1738 1734/1734/1734 +f 1736/1736/1736 1734/1734/1734 1738/1738/1738 +f 1558/1558/1558 1727/1727/1727 1723/1723/1723 +f 1724/1724/1724 1723/1723/1723 1727/1727/1727 +f 1735/1735/1735 1734/1734/1734 1728/1728/1728 +f 1727/1727/1727 1558/1558/1558 1728/1728/1728 +f 1726/1726/1726 1732/1732/1732 1731/1731/1731 +f 1486/1486/1486 1557/1557/1557 1530/1530/1530 +f 1485/1485/1485 1557/1557/1557 1486/1486/1486 +f 1730/1730/1730 1526/1526/1526 1725/1725/1725 +f 1557/1557/1557 1556/1556/1556 1530/1530/1530 +f 363/363/363 362/362/362 1533/1533/1533 +f 1546/1546/1546 1548/1548/1548 1651/1651/1651 +f 1533/1533/1533 1486/1486/1486 1523/1523/1523 +f 1515/1515/1515 1533/1533/1533 1523/1523/1523 +f 1527/1527/1527 1526/1526/1526 1739/1739/1739 +f 1739/1739/1739 1740/1740/1740 1527/1527/1527 +f 1741/1741/1741 1526/1526/1526 1730/1730/1730 +f 1741/1741/1741 1739/1739/1739 1526/1526/1526 +f 1725/1725/1725 1525/1525/1525 1723/1723/1723 +f 1525/1525/1525 1725/1725/1725 1526/1526/1526 +f 1528/1528/1528 1527/1527/1527 1740/1740/1740 +f 1740/1740/1740 1742/1742/1742 1528/1528/1528 +f 1734/1734/1734 1733/1733/1733 1737/1737/1737 +f 1743/1743/1743 1744/1744/1744 1745/1745/1745 +f 1744/1744/1744 1746/1746/1746 1745/1745/1745 +f 1743/1743/1743 1745/1745/1745 1521/1521/1521 +f 1747/1747/1747 1743/1743/1743 1748/1748/1748 +f 1743/1743/1743 1749/1749/1749 1744/1744/1744 +f 1749/1749/1749 1750/1750/1750 1751/1751/1751 +f 1744/1744/1744 1749/1749/1749 1746/1746/1746 +f 1749/1749/1749 1751/1751/1751 1746/1746/1746 +f 1752/1752/1752 1753/1753/1753 1754/1754/1754 +f 1754/1754/1754 1742/1742/1742 1752/1752/1752 +f 1748/1748/1748 1753/1753/1753 1747/1747/1747 +f 1755/1755/1755 1747/1747/1747 1753/1753/1753 +f 1732/1732/1732 1756/1756/1756 1752/1752/1752 +f 1748/1748/1748 1743/1743/1743 1521/1521/1521 +f 1753/1753/1753 1752/1752/1752 1755/1755/1755 +f 1756/1756/1756 1755/1755/1755 1752/1752/1752 +f 1743/1743/1743 1757/1757/1757 1749/1749/1749 +f 1758/1758/1758 1759/1759/1759 1545/1545/1545 +f 1552/1552/1552 1759/1759/1759 1551/1551/1551 +f 1545/1545/1545 1759/1759/1759 1552/1552/1552 +f 1760/1760/1760 1758/1758/1758 1545/1545/1545 +f 1738/1738/1738 1737/1737/1737 1758/1758/1758 +f 1551/1551/1551 1737/1737/1737 1733/1733/1733 +f 1737/1737/1737 1551/1551/1551 1759/1759/1759 +f 1759/1759/1759 1758/1758/1758 1737/1737/1737 +f 1761/1761/1761 1762/1762/1762 1749/1749/1749 +f 1762/1762/1762 1763/1763/1763 1750/1750/1750 +f 1749/1749/1749 1762/1762/1762 1750/1750/1750 +f 1757/1757/1757 1761/1761/1761 1749/1749/1749 +f 1764/1764/1764 1545/1545/1545 1762/1762/1762 +f 1764/1764/1764 1760/1760/1760 1545/1545/1545 +f 1761/1761/1761 1764/1764/1764 1762/1762/1762 +f 1762/1762/1762 1545/1545/1545 1763/1763/1763 +f 688/688/688 1765/1765/1765 687/687/687 +f 1766/1766/1766 687/687/687 1765/1765/1765 +f 1767/1767/1767 1768/1768/1768 700/700/700 +f 1766/1766/1766 1765/1765/1765 701/701/701 +f 1769/1769/1769 1770/1770/1770 694/694/694 +f 1770/1770/1770 695/695/695 694/694/694 +f 688/688/688 695/695/695 1765/1765/1765 +f 1770/1770/1770 1765/1765/1765 695/695/695 +f 1770/1770/1770 1767/1767/1767 701/701/701 +f 1765/1765/1765 1770/1770/1770 701/701/701 +f 1766/1766/1766 654/654/654 687/687/687 +f 701/701/701 654/654/654 1766/1766/1766 +f 1768/1768/1768 1767/1767/1767 1771/1771/1771 +f 329/329/329 700/700/700 1768/1768/1768 +f 652/652/652 654/654/654 701/701/701 +f 1767/1767/1767 700/700/700 701/701/701 +f 1771/1771/1771 1767/1767/1767 1769/1769/1769 +f 1371/1371/1371 1772/1772/1772 1375/1375/1375 +f 1772/1772/1772 1773/1773/1773 1375/1375/1375 +f 417/417/417 1773/1773/1773 638/638/638 +f 1772/1772/1772 638/638/638 1773/1773/1773 +f 702/702/702 1774/1774/1774 1368/1368/1368 +f 702/702/702 698/698/698 1774/1774/1774 +f 1374/1374/1374 1772/1772/1772 1371/1371/1371 +f 1374/1374/1374 1368/1368/1368 1774/1774/1774 +f 1775/1775/1775 699/699/699 640/640/640 +f 1774/1774/1774 1775/1775/1775 1374/1374/1374 +f 1770/1770/1770 1769/1769/1769 1767/1767/1767 +f 1772/1772/1772 1775/1775/1775 640/640/640 +f 1775/1775/1775 1774/1774/1774 699/699/699 +f 638/638/638 1772/1772/1772 640/640/640 +f 1775/1775/1775 1772/1772/1772 1374/1374/1374 +f 698/698/698 699/699/699 1774/1774/1774 +f 1776/1776/1776 1777/1777/1777 1778/1778/1778 +f 1519/1519/1519 1532/1532/1532 1779/1779/1779 +f 1519/1519/1519 1779/1779/1779 1780/1780/1780 +f 1779/1779/1779 1532/1532/1532 1781/1781/1781 +f 1780/1780/1780 1779/1779/1779 1527/1527/1527 +f 1513/1513/1513 1519/1519/1519 1780/1780/1780 +f 1518/1518/1518 1442/1442/1442 1519/1519/1519 +f 1780/1780/1780 1527/1527/1527 1517/1517/1517 +f 1780/1780/1780 1517/1517/1517 1513/1513/1513 +f 1529/1529/1529 1782/1782/1782 1531/1531/1531 +f 1782/1782/1782 1532/1532/1532 1531/1531/1531 +f 1651/1651/1651 1548/1548/1548 1538/1538/1538 +f 1548/1548/1548 1539/1539/1539 1538/1538/1538 +f 1529/1529/1529 1514/1514/1514 1782/1782/1782 +f 1514/1514/1514 1783/1783/1783 1782/1782/1782 +f 1783/1783/1783 1532/1532/1532 1782/1782/1782 +f 1783/1783/1783 1781/1781/1781 1532/1532/1532 +f 1784/1784/1784 1785/1785/1785 1786/1786/1786 +f 1778/1778/1778 1787/1787/1787 1788/1788/1788 +f 1789/1789/1789 1790/1790/1790 1776/1776/1776 +f 1777/1777/1777 1791/1791/1791 1778/1778/1778 +f 1788/1788/1788 1776/1776/1776 1778/1778/1778 +f 1790/1790/1790 1792/1792/1792 1777/1777/1777 +f 1793/1793/1793 1791/1791/1791 1777/1777/1777 +f 1790/1790/1790 1777/1777/1777 1776/1776/1776 +f 1792/1792/1792 1793/1793/1793 1777/1777/1777 +f 1794/1794/1794 1795/1795/1795 1786/1786/1786 +f 1796/1796/1796 1794/1794/1794 1786/1786/1786 +f 1795/1795/1795 1797/1797/1797 1784/1784/1784 +f 1784/1784/1784 1798/1798/1798 1785/1785/1785 +f 1789/1789/1789 1776/1776/1776 1788/1788/1788 +f 1788/1788/1788 1787/1787/1787 1799/1799/1799 +f 1786/1786/1786 1795/1795/1795 1784/1784/1784 +f 1789/1789/1789 1788/1788/1788 1800/1800/1800 +f 1753/1753/1753 1748/1748/1748 1754/1754/1754 +f 1648/1648/1648 1801/1801/1801 1643/1643/1643 +f 1647/1647/1647 1635/1635/1635 1641/1641/1641 +f 1801/1801/1801 1648/1648/1648 1288/1288/1288 +f 1553/1553/1553 1801/1801/1801 1288/1288/1288 +f 1647/1647/1647 1634/1634/1634 1635/1635/1635 +f 1802/1802/1802 1634/1634/1634 1647/1647/1647 +f 1553/1553/1553 1647/1647/1647 1801/1801/1801 +f 1652/1652/1652 1802/1802/1802 1647/1647/1647 +f 1395/1395/1395 1398/1398/1398 1587/1587/1587 +f 1396/1396/1396 1644/1644/1644 1398/1398/1398 +f 1362/1362/1362 1590/1590/1590 1352/1352/1352 +f 1352/1352/1352 1590/1590/1590 1351/1351/1351 +f 1288/1288/1288 1648/1648/1648 1289/1289/1289 +f 1643/1643/1643 1645/1645/1645 1289/1289/1289 +f 1587/1587/1587 1398/1398/1398 1646/1646/1646 +f 1644/1644/1644 1396/1396/1396 1645/1645/1645 +f 1643/1643/1643 1801/1801/1801 1647/1647/1647 +f 1803/1803/1803 1540/1540/1540 1804/1804/1804 +f 1803/1803/1803 1804/1804/1804 1805/1805/1805 +f 1722/1722/1722 1650/1650/1650 1803/1803/1803 +f 1485/1485/1485 1804/1804/1804 1540/1540/1540 +f 1806/1806/1806 1807/1807/1807 1804/1804/1804 +f 1808/1808/1808 764/764/764 1806/1806/1806 +f 1804/1804/1804 1807/1807/1807 1805/1805/1805 +f 1809/1809/1809 1804/1804/1804 1485/1485/1485 +f 1722/1722/1722 1810/1810/1810 1811/1811/1811 +f 1650/1650/1650 1722/1722/1722 1811/1811/1811 +f 1811/1811/1811 1652/1652/1652 1651/1651/1651 +f 1811/1811/1811 1651/1651/1651 1650/1650/1650 +f 1810/1810/1810 1628/1628/1628 1802/1802/1802 +f 1802/1802/1802 1628/1628/1628 1634/1634/1634 +f 1810/1810/1810 1802/1802/1802 1652/1652/1652 +f 1811/1811/1811 1810/1810/1810 1652/1652/1652 +f 1590/1590/1590 1585/1585/1585 1351/1351/1351 +f 1812/1812/1812 1807/1807/1807 1582/1582/1582 +f 1807/1807/1807 1813/1813/1813 1583/1583/1583 +f 1629/1629/1629 1628/1628/1628 1582/1582/1582 +f 1582/1582/1582 1628/1628/1628 1812/1812/1812 +f 1581/1581/1581 1580/1580/1580 1583/1583/1583 +f 1597/1597/1597 1582/1582/1582 1580/1580/1580 +f 1582/1582/1582 1807/1807/1807 1583/1583/1583 +f 1597/1597/1597 1629/1629/1629 1582/1582/1582 +f 1722/1722/1722 1628/1628/1628 1810/1810/1810 +f 1812/1812/1812 1628/1628/1628 1721/1721/1721 +f 1634/1634/1634 1628/1628/1628 1637/1637/1637 +f 1624/1624/1624 1637/1637/1637 1628/1628/1628 +f 1803/1803/1803 1805/1805/1805 1722/1722/1722 +f 1722/1722/1722 1805/1805/1805 1721/1721/1721 +f 1807/1807/1807 1721/1721/1721 1805/1805/1805 +f 1812/1812/1812 1721/1721/1721 1807/1807/1807 +f 1806/1806/1806 1814/1814/1814 1807/1807/1807 +f 1584/1584/1584 1815/1815/1815 1585/1585/1585 +f 1583/1583/1583 1813/1813/1813 1581/1581/1581 +f 1815/1815/1815 829/829/829 1816/1816/1816 +f 1816/1816/1816 1585/1585/1585 1815/1815/1815 +f 1351/1351/1351 1585/1585/1585 1816/1816/1816 +f 1284/1284/1284 1351/1351/1351 1816/1816/1816 +f 1584/1584/1584 1581/1581/1581 1813/1813/1813 +f 1284/1284/1284 1816/1816/1816 245/245/245 +f 828/828/828 1817/1817/1817 1814/1814/1814 +f 1817/1817/1817 1813/1813/1813 1807/1807/1807 +f 1815/1815/1815 1584/1584/1584 1813/1813/1813 +f 1814/1814/1814 764/764/764 828/828/828 +f 1817/1817/1817 1815/1815/1815 1813/1813/1813 +f 245/245/245 1816/1816/1816 829/829/829 +f 829/829/829 1815/1815/1815 828/828/828 +f 1817/1817/1817 828/828/828 1815/1815/1815 +f 1818/1818/1818 1757/1757/1757 1819/1819/1819 +f 1757/1757/1757 1743/1743/1743 1819/1819/1819 +f 1743/1743/1743 1747/1747/1747 1820/1820/1820 +f 1820/1820/1820 1819/1819/1819 1743/1743/1743 +f 1764/1764/1764 1761/1761/1761 1821/1821/1821 +f 1822/1822/1822 1764/1764/1764 1821/1821/1821 +f 1761/1761/1761 1757/1757/1757 1818/1818/1818 +f 1818/1818/1818 1821/1821/1821 1761/1761/1761 +f 1750/1750/1750 1763/1763/1763 1823/1823/1823 +f 1824/1824/1824 1820/1820/1820 1747/1747/1747 +f 1545/1545/1545 1823/1823/1823 1763/1763/1763 +f 1751/1751/1751 1750/1750/1750 1823/1823/1823 +f 1755/1755/1755 1756/1756/1756 1824/1824/1824 +f 1756/1756/1756 1732/1732/1732 1825/1825/1825 +f 1747/1747/1747 1755/1755/1755 1824/1824/1824 +f 1825/1825/1825 1824/1824/1824 1756/1756/1756 +f 1760/1760/1760 1764/1764/1764 1822/1822/1822 +f 1739/1739/1739 1741/1741/1741 1731/1731/1731 +f 1740/1740/1740 1739/1739/1739 1731/1731/1731 +f 1732/1732/1732 1729/1729/1729 1825/1825/1825 +f 1741/1741/1741 1730/1730/1730 1731/1731/1731 +f 1742/1742/1742 1740/1740/1740 1752/1752/1752 +f 1521/1521/1521 1754/1754/1754 1748/1748/1748 +f 1732/1732/1732 1752/1752/1752 1731/1731/1731 +f 1731/1731/1731 1752/1752/1752 1740/1740/1740 +f 1736/1736/1736 1738/1738/1738 1822/1822/1822 +f 1822/1822/1822 1826/1826/1826 1736/1736/1736 +f 1758/1758/1758 1760/1760/1760 1822/1822/1822 +f 1738/1738/1738 1758/1758/1758 1822/1822/1822 +f 1729/1729/1729 1728/1728/1728 1827/1827/1827 +f 1827/1827/1827 1825/1825/1825 1729/1729/1729 +f 1728/1728/1728 1736/1736/1736 1826/1826/1826 +f 1826/1826/1826 1827/1827/1827 1728/1728/1728 +f 1521/1521/1521 1511/1511/1511 1754/1754/1754 +f 1485/1485/1485 465/465/465 1809/1809/1809 +f 1723/1723/1723 1525/1525/1525 1558/1558/1558 +f 1540/1540/1540 1803/1803/1803 1538/1538/1538 +f 1803/1803/1803 1650/1650/1650 1538/1538/1538 +f 1828/1828/1828 1733/1733/1733 1735/1735/1735 +f 1733/1733/1733 1828/1828/1828 1551/1551/1551 +f 1558/1558/1558 1735/1735/1735 1728/1728/1728 +f 1735/1735/1735 1558/1558/1558 1828/1828/1828 +f 1808/1808/1808 1806/1806/1806 1809/1809/1809 +f 1808/1808/1808 1809/1809/1809 763/763/763 +f 1809/1809/1809 465/465/465 763/763/763 +f 1809/1809/1809 1806/1806/1806 1804/1804/1804 +f 763/763/763 764/764/764 1808/1808/1808 +f 1651/1651/1651 1553/1553/1553 1546/1546/1546 +f 764/764/764 1814/1814/1814 1806/1806/1806 +f 1814/1814/1814 1817/1817/1817 1807/1807/1807 +f 1551/1551/1551 1828/1828/1828 1549/1549/1549 +f 1514/1514/1514 1526/1526/1526 1781/1781/1781 +f 1526/1526/1526 1527/1527/1527 1779/1779/1779 +f 1829/1829/1829 1746/1746/1746 1751/1751/1751 +f 1781/1781/1781 1783/1783/1783 1514/1514/1514 +f 1511/1511/1511 1517/1517/1517 1742/1742/1742 +f 1754/1754/1754 1511/1511/1511 1742/1742/1742 +f 1781/1781/1781 1526/1526/1526 1779/1779/1779 +f 1517/1517/1517 1528/1528/1528 1742/1742/1742 +f 1746/1746/1746 1829/1829/1829 1745/1745/1745 +f 1829/1829/1829 1830/1830/1830 1745/1745/1745 +f 1558/1558/1558 1549/1549/1549 1828/1828/1828 +f 1552/1552/1552 1551/1551/1551 1547/1547/1547 +f 1831/1831/1831 1830/1830/1830 1832/1832/1832 +f 1830/1830/1830 1829/1829/1829 1832/1832/1832 +f 1745/1745/1745 1830/1830/1830 1521/1521/1521 +f 1830/1830/1830 1831/1831/1831 1521/1521/1521 +f 1833/1833/1833 1834/1834/1834 1835/1835/1835 +f 1836/1836/1836 1837/1837/1837 1838/1838/1838 +f 1837/1837/1837 1839/1839/1839 1838/1838/1838 +f 1836/1836/1836 1840/1840/1840 1841/1841/1841 +f 1840/1840/1840 1834/1834/1834 1841/1841/1841 +f 1836/1836/1836 1838/1838/1838 1840/1840/1840 +f 1842/1842/1842 1834/1834/1834 1843/1843/1843 +f 1841/1841/1841 1834/1834/1834 1844/1844/1844 +f 1844/1844/1844 1845/1845/1845 1841/1841/1841 +f 1836/1836/1836 1841/1841/1841 1837/1837/1837 +f 1842/1842/1842 1846/1846/1846 1844/1844/1844 +f 1844/1844/1844 1834/1834/1834 1842/1842/1842 +f 1833/1833/1833 1847/1847/1847 1834/1834/1834 +f 1848/1848/1848 1849/1849/1849 1850/1850/1850 +f 1849/1849/1849 1851/1851/1851 1850/1850/1850 +f 1852/1852/1852 1853/1853/1853 1854/1854/1854 +f 1851/1851/1851 1855/1855/1855 1856/1856/1856 +f 1856/1856/1856 1855/1855/1855 1857/1857/1857 +f 1852/1852/1852 1850/1850/1850 1835/1835/1835 +f 1839/1839/1839 1852/1852/1852 1838/1838/1838 +f 1839/1839/1839 1853/1853/1853 1852/1852/1852 +f 1852/1852/1852 1835/1835/1835 1838/1838/1838 +f 1848/1848/1848 1852/1852/1852 1854/1854/1854 +f 1840/1840/1840 1835/1835/1835 1834/1834/1834 +f 1838/1838/1838 1835/1835/1835 1840/1840/1840 +f 1858/1858/1858 1859/1859/1859 1860/1860/1860 +f 1861/1861/1861 1862/1862/1862 1863/1863/1863 +f 1863/1863/1863 1862/1862/1862 1864/1864/1864 +f 1865/1865/1865 1866/1866/1866 1864/1864/1864 +f 1859/1859/1859 1867/1867/1867 1866/1866/1866 +f 1868/1868/1868 1869/1869/1869 1864/1864/1864 +f 1870/1870/1870 1871/1871/1871 1872/1872/1872 +f 1872/1872/1872 1871/1871/1871 1873/1873/1873 +f 1871/1871/1871 1870/1870/1870 1865/1865/1865 +f 1874/1874/1874 1863/1863/1863 1864/1864/1864 +f 1864/1864/1864 1862/1862/1862 1871/1871/1871 +f 1865/1865/1865 1864/1864/1864 1871/1871/1871 +f 1869/1869/1869 1874/1874/1874 1864/1864/1864 +f 1875/1875/1875 1876/1876/1876 1877/1877/1877 +f 1877/1877/1877 1846/1846/1846 1875/1875/1875 +f 1878/1878/1878 1877/1877/1877 1869/1869/1869 +f 1845/1845/1845 1837/1837/1837 1841/1841/1841 +f 1869/1869/1869 1877/1877/1877 1874/1874/1874 +f 1877/1877/1877 1876/1876/1876 1874/1874/1874 +f 1867/1867/1867 1868/1868/1868 1866/1866/1866 +f 1867/1867/1867 1879/1879/1879 1868/1868/1868 +f 1866/1866/1866 1868/1868/1868 1864/1864/1864 +f 1880/1880/1880 1844/1844/1844 1846/1846/1846 +f 1881/1881/1881 1877/1877/1877 1878/1878/1878 +f 1878/1878/1878 1869/1869/1869 1868/1868/1868 +f 1835/1835/1835 1856/1856/1856 1833/1833/1833 +f 1859/1859/1859 1858/1858/1858 1882/1882/1882 +f 1867/1867/1867 1883/1883/1883 1884/1884/1884 +f 1885/1885/1885 1886/1886/1886 1887/1887/1887 +f 1888/1888/1888 1889/1889/1889 1858/1858/1858 +f 1858/1858/1858 1889/1889/1889 1882/1882/1882 +f 1883/1883/1883 1882/1882/1882 1890/1890/1890 +f 1886/1886/1886 1885/1885/1885 1890/1890/1890 +f 1891/1891/1891 1890/1890/1890 1892/1892/1892 +f 1890/1890/1890 1885/1885/1885 1892/1892/1892 +f 1889/1889/1889 1888/1888/1888 1887/1887/1887 +f 1887/1887/1887 1888/1888/1888 1893/1893/1893 +f 1886/1886/1886 1890/1890/1890 1889/1889/1889 +f 1886/1886/1886 1889/1889/1889 1887/1887/1887 +f 1894/1894/1894 1895/1895/1895 1896/1896/1896 +f 1897/1897/1897 1898/1898/1898 1879/1879/1879 +f 1879/1879/1879 1867/1867/1867 1884/1884/1884 +f 1899/1899/1899 1900/1900/1900 1897/1897/1897 +f 1896/1896/1896 1901/1901/1901 1902/1902/1902 +f 1879/1879/1879 1896/1896/1896 1902/1902/1902 +f 1903/1903/1903 1904/1904/1904 1905/1905/1905 +f 1882/1882/1882 1883/1883/1883 1867/1867/1867 +f 1867/1867/1867 1859/1859/1859 1882/1882/1882 +f 1906/1906/1906 1907/1907/1907 1894/1894/1894 +f 1906/1906/1906 1894/1894/1894 1896/1896/1896 +f 1905/1905/1905 1879/1879/1879 1884/1884/1884 +f 1855/1855/1855 1849/1849/1849 1908/1908/1908 +f 1855/1855/1855 1851/1851/1851 1849/1849/1849 +f 1852/1852/1852 1848/1848/1848 1850/1850/1850 +f 1909/1909/1909 1910/1910/1910 1911/1911/1911 +f 1850/1850/1850 1851/1851/1851 1856/1856/1856 +f 1912/1912/1912 1855/1855/1855 1908/1908/1908 +f 1849/1849/1849 1848/1848/1848 1854/1854/1854 +f 1913/1913/1913 1849/1849/1849 1854/1854/1854 +f 1850/1850/1850 1856/1856/1856 1835/1835/1835 +f 1908/1908/1908 1849/1849/1849 1911/1911/1911 +f 1849/1849/1849 1913/1913/1913 1909/1909/1909 +f 1911/1911/1911 1849/1849/1849 1909/1909/1909 +f 1910/1910/1910 1903/1903/1903 1891/1891/1891 +f 1914/1914/1914 1915/1915/1915 1912/1912/1912 +f 1908/1908/1908 1914/1914/1914 1912/1912/1912 +f 1914/1914/1914 1885/1885/1885 1915/1915/1915 +f 1882/1882/1882 1889/1889/1889 1890/1890/1890 +f 1903/1903/1903 1883/1883/1883 1891/1891/1891 +f 1883/1883/1883 1890/1890/1890 1891/1891/1891 +f 1911/1911/1911 1910/1910/1910 1908/1908/1908 +f 1910/1910/1910 1891/1891/1891 1892/1892/1892 +f 1885/1885/1885 1914/1914/1914 1892/1892/1892 +f 1887/1887/1887 1915/1915/1915 1885/1885/1885 +f 1914/1914/1914 1908/1908/1908 1892/1892/1892 +f 1910/1910/1910 1892/1892/1892 1908/1908/1908 +f 1866/1866/1866 1865/1865/1865 1870/1870/1870 +f 1707/1707/1707 1916/1916/1916 1917/1917/1917 +f 1917/1917/1917 1691/1691/1691 1707/1707/1707 +f 1707/1707/1707 1697/1697/1697 1918/1918/1918 +f 1916/1916/1916 1707/1707/1707 1919/1919/1919 +f 1918/1918/1918 1919/1919/1919 1707/1707/1707 +f 1916/1916/1916 1920/1920/1920 1917/1917/1917 +f 1921/1921/1921 1920/1920/1920 1922/1922/1922 +f 1923/1923/1923 1922/1922/1922 1920/1920/1920 +f 1921/1921/1921 1924/1924/1924 1917/1917/1917 +f 1925/1925/1925 1697/1697/1697 1681/1681/1681 +f 1921/1921/1921 1922/1922/1922 1926/1926/1926 +f 1927/1927/1927 1921/1921/1921 1926/1926/1926 +f 1928/1928/1928 1916/1916/1916 1929/1929/1929 +f 1930/1930/1930 986/986/986 647/647/647 +f 1931/1931/1931 1930/1930/1930 647/647/647 +f 1930/1930/1930 1932/1932/1932 986/986/986 +f 1931/1931/1931 1694/1694/1694 1918/1918/1918 +f 1930/1930/1930 1931/1931/1931 1697/1697/1697 +f 1918/1918/1918 1697/1697/1697 1931/1931/1931 +f 1916/1916/1916 1928/1928/1928 1920/1920/1920 +f 1923/1923/1923 1920/1920/1920 1928/1928/1928 +f 1916/1916/1916 1919/1919/1919 1929/1929/1929 +f 987/987/987 986/986/986 1932/1932/1932 +f 1930/1930/1930 1697/1697/1697 1925/1925/1925 +f 1932/1932/1932 1930/1930/1930 1925/1925/1925 +f 1933/1933/1933 1934/1934/1934 1688/1688/1688 +f 1683/1683/1683 1688/1688/1688 1684/1684/1684 +f 1935/1935/1935 1933/1933/1933 1688/1688/1688 +f 1933/1933/1933 1936/1936/1936 1937/1937/1937 +f 1934/1934/1934 1933/1933/1933 1937/1937/1937 +f 1927/1927/1927 1938/1938/1938 1936/1936/1936 +f 1685/1685/1685 1684/1684/1684 1692/1692/1692 +f 1692/1692/1692 1684/1684/1684 1693/1693/1693 +f 1684/1684/1684 1939/1939/1939 1693/1693/1693 +f 1939/1939/1939 1940/1940/1940 1695/1695/1695 +f 1939/1939/1939 1934/1934/1934 1940/1940/1940 +f 1937/1937/1937 1940/1940/1940 1934/1934/1934 +f 1689/1689/1689 1682/1682/1682 1687/1687/1687 +f 1691/1691/1691 1924/1924/1924 1935/1935/1935 +f 1690/1690/1690 1691/1691/1691 1935/1935/1935 +f 1917/1917/1917 1924/1924/1924 1691/1691/1691 +f 1920/1920/1920 1921/1921/1921 1917/1917/1917 +f 1921/1921/1921 1927/1927/1927 1924/1924/1924 +f 1935/1935/1935 1924/1924/1924 1927/1927/1927 +f 1687/1687/1687 1935/1935/1935 1688/1688/1688 +f 1687/1687/1687 1690/1690/1690 1935/1935/1935 +f 1687/1687/1687 1682/1682/1682 1690/1690/1690 +f 1933/1933/1933 1927/1927/1927 1936/1936/1936 +f 1926/1926/1926 1938/1938/1938 1927/1927/1927 +f 1927/1927/1927 1933/1933/1933 1935/1935/1935 +f 1694/1694/1694 1919/1919/1919 1918/1918/1918 +f 1941/1941/1941 1942/1942/1942 1943/1943/1943 +f 1942/1942/1942 1941/1941/1941 1944/1944/1944 +f 1944/1944/1944 1475/1475/1475 1945/1945/1945 +f 1943/1943/1943 1946/1946/1946 1947/1947/1947 +f 1948/1948/1948 1947/1947/1947 1946/1946/1946 +f 1946/1946/1946 1943/1943/1943 1949/1949/1949 +f 1947/1947/1947 1950/1950/1950 1951/1951/1951 +f 1941/1941/1941 1947/1947/1947 1951/1951/1951 +f 1952/1952/1952 1941/1941/1941 1951/1951/1951 +f 1941/1941/1941 1952/1952/1952 1944/1944/1944 +f 1947/1947/1947 1948/1948/1948 1950/1950/1950 +f 1923/1923/1923 1950/1950/1950 1948/1948/1948 +f 1474/1474/1474 1953/1953/1953 1475/1475/1475 +f 1954/1954/1954 1862/1862/1862 1861/1861/1861 +f 1955/1955/1955 1954/1954/1954 1861/1861/1861 +f 1954/1954/1954 1873/1873/1873 1862/1862/1862 +f 1870/1870/1870 1945/1945/1945 1956/1956/1956 +f 1954/1954/1954 1955/1955/1955 1943/1943/1943 +f 1949/1949/1949 1943/1943/1943 1955/1955/1955 +f 1871/1871/1871 1862/1862/1862 1873/1873/1873 +f 1872/1872/1872 1945/1945/1945 1870/1870/1870 +f 1860/1860/1860 1870/1870/1870 1956/1956/1956 +f 1873/1873/1873 1954/1954/1954 1942/1942/1942 +f 1872/1872/1872 1873/1873/1873 1942/1942/1942 +f 1954/1954/1954 1943/1943/1943 1942/1942/1942 +f 1957/1957/1957 1958/1958/1958 1959/1959/1959 +f 1960/1960/1960 1959/1959/1959 1958/1958/1958 +f 1957/1957/1957 646/646/646 968/968/968 +f 1929/1929/1929 1959/1959/1959 1928/1928/1928 +f 1957/1957/1957 1959/1959/1959 1929/1929/1929 +f 1961/1961/1961 1957/1957/1957 1929/1929/1929 +f 1929/1929/1929 1919/1919/1919 1961/1961/1961 +f 1961/1961/1961 1694/1694/1694 646/646/646 +f 1694/1694/1694 1931/1931/1931 647/647/647 +f 1958/1958/1958 1957/1957/1957 968/968/968 +f 1957/1957/1957 1961/1961/1961 646/646/646 +f 1694/1694/1694 1961/1961/1961 1919/1919/1919 +f 1962/1962/1962 1928/1928/1928 1959/1959/1959 +f 1951/1951/1951 1962/1962/1962 1960/1960/1960 +f 1963/1963/1963 1960/1960/1960 1958/1958/1958 +f 1960/1960/1960 1963/1963/1963 1964/1964/1964 +f 1943/1943/1943 1947/1947/1947 1941/1941/1941 +f 1965/1965/1965 1951/1951/1951 1964/1964/1964 +f 1964/1964/1964 1951/1951/1951 1960/1960/1960 +f 1928/1928/1928 1962/1962/1962 1923/1923/1923 +f 1950/1950/1950 1962/1962/1962 1951/1951/1951 +f 1960/1960/1960 1962/1962/1962 1959/1959/1959 +f 1963/1963/1963 968/968/968 939/939/939 +f 1963/1963/1963 1958/1958/1958 968/968/968 +f 1962/1962/1962 1950/1950/1950 1923/1923/1923 +f 1966/1966/1966 1899/1899/1899 1897/1897/1897 +f 1967/1967/1967 1968/1968/1968 1969/1969/1969 +f 1970/1970/1970 1969/1969/1969 1968/1968/1968 +f 1967/1967/1967 1372/1372/1372 1375/1375/1375 +f 1375/1375/1375 1773/1773/1773 1968/1968/1968 +f 1971/1971/1971 1972/1972/1972 1970/1970/1970 +f 1968/1968/1968 1971/1971/1971 1970/1970/1970 +f 1967/1967/1967 1969/1969/1969 691/691/691 +f 1973/1973/1973 1967/1967/1967 691/691/691 +f 1974/1974/1974 1018/1018/1018 987/987/987 +f 1968/1968/1968 1967/1967/1967 1375/1375/1375 +f 1967/1967/1967 1973/1973/1973 1372/1372/1372 +f 1373/1373/1373 1372/1372/1372 1973/1973/1973 +f 1971/1971/1971 1968/1968/1968 1773/1773/1773 +f 1975/1975/1975 1976/1976/1976 1977/1977/1977 +f 1976/1976/1976 1768/1768/1768 1771/1771/1771 +f 1978/1978/1978 1976/1976/1976 1771/1771/1771 +f 1975/1975/1975 996/996/996 1020/1020/1020 +f 1976/1976/1976 1975/1975/1975 1020/1020/1020 +f 1976/1976/1976 1978/1978/1978 1977/1977/1977 +f 1014/1014/1014 1972/1972/1972 1021/1021/1021 +f 1971/1971/1971 1773/1773/1773 417/417/417 +f 1021/1021/1021 1971/1971/1971 417/417/417 +f 1976/1976/1976 1020/1020/1020 329/329/329 +f 1768/1768/1768 1976/1976/1976 329/329/329 +f 1971/1971/1971 1021/1021/1021 1972/1972/1972 +f 1795/1795/1795 1791/1791/1791 1797/1797/1797 +f 1795/1795/1795 1979/1979/1979 1791/1791/1791 +f 1793/1793/1793 1792/1792/1792 1797/1797/1797 +f 689/689/689 1980/1980/1980 1681/1681/1681 +f 1981/1981/1981 1787/1787/1787 1778/1778/1778 +f 1791/1791/1791 1979/1979/1979 1982/1982/1982 +f 1983/1983/1983 1789/1789/1789 1984/1984/1984 +f 1983/1983/1983 1985/1985/1985 1789/1789/1789 +f 1985/1985/1985 1983/1983/1983 1986/1986/1986 +f 1791/1791/1791 1793/1793/1793 1797/1797/1797 +f 1797/1797/1797 1792/1792/1792 1784/1784/1784 +f 1987/1987/1987 1983/1983/1983 1984/1984/1984 +f 691/691/691 1969/1969/1969 689/689/689 +f 1974/1974/1974 1988/1988/1988 1972/1972/1972 +f 1970/1970/1970 1972/1972/1972 1988/1988/1988 +f 1974/1974/1974 1932/1932/1932 1988/1988/1988 +f 1932/1932/1932 1974/1974/1974 987/987/987 +f 1018/1018/1018 1974/1974/1974 1014/1014/1014 +f 1972/1972/1972 1014/1014/1014 1974/1974/1974 +f 1980/1980/1980 1969/1969/1969 1970/1970/1970 +f 1988/1988/1988 1980/1980/1980 1970/1970/1970 +f 1980/1980/1980 689/689/689 1969/1969/1969 +f 1925/1925/1925 1988/1988/1988 1932/1932/1932 +f 1980/1980/1980 1988/1988/1988 1925/1925/1925 +f 1681/1681/1681 1980/1980/1980 1925/1925/1925 +f 1977/1977/1977 1989/1989/1989 1975/1975/1975 +f 1990/1990/1990 1991/1991/1991 1992/1992/1992 +f 1992/1992/1992 1991/1991/1991 1993/1993/1993 +f 1994/1994/1994 1992/1992/1992 693/693/693 +f 1369/1369/1369 1995/1995/1995 680/680/680 +f 1995/1995/1995 1993/1993/1993 680/680/680 +f 1994/1994/1994 1996/1996/1996 1689/1689/1689 +f 1686/1686/1686 1689/1689/1689 1683/1683/1683 +f 1686/1686/1686 1992/1992/1992 1994/1994/1994 +f 1992/1992/1992 1686/1686/1686 1997/1997/1997 +f 680/680/680 1993/1993/1993 678/678/678 +f 1993/1993/1993 1991/1991/1991 678/678/678 +f 1994/1994/1994 1689/1689/1689 1686/1686/1686 +f 693/693/693 1993/1993/1993 1995/1995/1995 +f 691/691/691 690/690/690 1973/1973/1973 +f 1998/1998/1998 1386/1386/1386 1373/1373/1373 +f 1973/1973/1973 1998/1998/1998 1373/1373/1373 +f 1998/1998/1998 690/690/690 693/693/693 +f 1995/1995/1995 1998/1998/1998 693/693/693 +f 1998/1998/1998 1973/1973/1973 690/690/690 +f 693/693/693 692/692/692 1996/1996/1996 +f 692/692/692 1689/1689/1689 1996/1996/1996 +f 693/693/693 1992/1992/1992 1993/1993/1993 +f 1998/1998/1998 1995/1995/1995 1386/1386/1386 +f 1369/1369/1369 1386/1386/1386 1995/1995/1995 +f 1682/1682/1682 1689/1689/1689 692/692/692 +f 1999/1999/1999 2000/2000/2000 1997/1997/1997 +f 2001/2001/2001 1999/1999/1999 1997/1997/1997 +f 1999/1999/1999 1769/1769/1769 2000/2000/2000 +f 2001/2001/2001 2002/2002/2002 1977/1977/1977 +f 1999/1999/1999 2001/2001/2001 1978/1978/1978 +f 1977/1977/1977 1978/1978/1978 2001/2001/2001 +f 996/996/996 1989/1989/1989 2003/2003/2003 +f 941/941/941 996/996/996 2003/2003/2003 +f 996/996/996 1975/1975/1975 1989/1989/1989 +f 694/694/694 2000/2000/2000 1769/1769/1769 +f 1999/1999/1999 1978/1978/1978 1771/1771/1771 +f 1769/1769/1769 1999/1999/1999 1771/1771/1771 +f 2002/2002/2002 1989/1989/1989 1977/1977/1977 +f 1990/1990/1990 696/696/696 1991/1991/1991 +f 678/678/678 1991/1991/1991 696/696/696 +f 1990/1990/1990 2000/2000/2000 694/694/694 +f 1990/1990/1990 1992/1992/1992 2000/2000/2000 +f 1997/1997/1997 2000/2000/2000 1992/1992/1992 +f 1996/1996/1996 1994/1994/1994 693/693/693 +f 2004/2004/2004 2002/2002/2002 1686/1686/1686 +f 2002/2002/2002 2001/2001/2001 1686/1686/1686 +f 1997/1997/1997 1686/1686/1686 2001/2001/2001 +f 696/696/696 1990/1990/1990 694/694/694 +f 2002/2002/2002 2004/2004/2004 1989/1989/1989 +f 2003/2003/2003 1989/1989/1989 2004/2004/2004 +f 1789/1789/1789 1985/1985/1985 2005/2005/2005 +f 1986/1986/1986 2006/2006/2006 2007/2007/2007 +f 2006/2006/2006 1986/1986/1986 1987/1987/1987 +f 1987/1987/1987 1986/1986/1986 1983/1983/1983 +f 2008/2008/2008 2006/2006/2006 2009/2009/2009 +f 1987/1987/1987 2009/2009/2009 2006/2006/2006 +f 2007/2007/2007 2010/2010/2010 1986/1986/1986 +f 2010/2010/2010 2007/2007/2007 2011/2011/2011 +f 2008/2008/2008 2012/2012/2012 2006/2006/2006 +f 2006/2006/2006 2012/2012/2012 2007/2007/2007 +f 1853/1853/1853 1839/1839/1839 2012/2012/2012 +f 1854/1854/1854 1853/1853/1853 2012/2012/2012 +f 2012/2012/2012 1839/1839/1839 2007/2007/2007 +f 1913/1913/1913 2008/2008/2008 1909/1909/1909 +f 1904/1904/1904 1903/1903/1903 1910/1910/1910 +f 1910/1910/1910 2009/2009/2009 2013/2013/2013 +f 1987/1987/1987 2013/2013/2013 2009/2009/2009 +f 1894/1894/1894 1907/1907/1907 1895/1895/1895 +f 1895/1895/1895 2014/2014/2014 1896/1896/1896 +f 2009/2009/2009 1910/1910/1910 1909/1909/1909 +f 2008/2008/2008 1913/1913/1913 2012/2012/2012 +f 1854/1854/1854 2012/2012/2012 1913/1913/1913 +f 2008/2008/2008 2009/2009/2009 1909/1909/1909 +f 1904/1904/1904 1910/1910/1910 2013/2013/2013 +f 2013/2013/2013 2015/2015/2015 1907/1907/1907 +f 2013/2013/2013 1987/1987/1987 2015/2015/2015 +f 2016/2016/2016 1880/1880/1880 1900/1900/1900 +f 1880/1880/1880 1881/1881/1881 1900/1900/1900 +f 1879/1879/1879 1898/1898/1898 1868/1868/1868 +f 1785/1785/1785 2017/2017/2017 2018/2018/2018 +f 1881/1881/1881 1880/1880/1880 1846/1846/1846 +f 1878/1878/1878 1900/1900/1900 1881/1881/1881 +f 2019/2019/2019 1898/1898/1898 1900/1900/1900 +f 1900/1900/1900 1898/1898/1898 1897/1897/1897 +f 1897/1897/1897 1879/1879/1879 1966/1966/1966 +f 2019/2019/2019 1868/1868/1868 1898/1898/1898 +f 1878/1878/1878 1868/1868/1868 2019/2019/2019 +f 1878/1878/1878 2019/2019/2019 1900/1900/1900 +f 2018/2018/2018 1880/1880/1880 2016/2016/2016 +f 2007/2007/2007 1839/1839/1839 2011/2011/2011 +f 2005/2005/2005 1985/1985/1985 2010/2010/2010 +f 2010/2010/2010 2011/2011/2011 2020/2020/2020 +f 1986/1986/1986 2010/2010/2010 1985/1985/1985 +f 2011/2011/2011 1839/1839/1839 1845/1845/1845 +f 2020/2020/2020 2011/2011/2011 1845/1845/1845 +f 2017/2017/2017 2005/2005/2005 2020/2020/2020 +f 1877/1877/1877 1881/1881/1881 1846/1846/1846 +f 1880/1880/1880 1845/1845/1845 1844/1844/1844 +f 1845/1845/1845 1839/1839/1839 1837/1837/1837 +f 1845/1845/1845 1880/1880/1880 2018/2018/2018 +f 1845/1845/1845 2017/2017/2017 2020/2020/2020 +f 1896/1896/1896 1879/1879/1879 1905/1905/1905 +f 1966/1966/1966 1902/1902/1902 1796/1796/1796 +f 1786/1786/1786 1966/1966/1966 1796/1796/1796 +f 1966/1966/1966 1879/1879/1879 1902/1902/1902 +f 1901/1901/1901 2021/2021/2021 1902/1902/1902 +f 1899/1899/1899 1966/1966/1966 1786/1786/1786 +f 1900/1900/1900 1899/1899/1899 1786/1786/1786 +f 1796/1796/1796 1902/1902/1902 1794/1794/1794 +f 1979/1979/1979 2021/2021/2021 2022/2022/2022 +f 1794/1794/1794 1979/1979/1979 1795/1795/1795 +f 1794/1794/1794 1902/1902/1902 2021/2021/2021 +f 1794/1794/1794 2021/2021/2021 1979/1979/1979 +f 1982/1982/1982 1979/1979/1979 2022/2022/2022 +f 2018/2018/2018 2023/2023/2023 1786/1786/1786 +f 1789/1789/1789 2005/2005/2005 1790/1790/1790 +f 1798/1798/1798 2005/2005/2005 2017/2017/2017 +f 1798/1798/1798 1784/1784/1784 1792/1792/1792 +f 1798/1798/1798 1790/1790/1790 2005/2005/2005 +f 2005/2005/2005 2010/2010/2010 2020/2020/2020 +f 1790/1790/1790 1798/1798/1798 1792/1792/1792 +f 2023/2023/2023 2016/2016/2016 1900/1900/1900 +f 2023/2023/2023 2018/2018/2018 2016/2016/2016 +f 2023/2023/2023 1900/1900/1900 1786/1786/1786 +f 2017/2017/2017 1845/1845/1845 2018/2018/2018 +f 1798/1798/1798 2017/2017/2017 1785/1785/1785 +f 2018/2018/2018 1786/1786/1786 1785/1785/1785 +f 2015/2015/2015 1789/1789/1789 2024/2024/2024 +f 1789/1789/1789 2015/2015/2015 1984/1984/1984 +f 1987/1987/1987 1984/1984/1984 2015/2015/2015 +f 2024/2024/2024 2014/2014/2014 1895/1895/1895 +f 2024/2024/2024 1895/1895/1895 2015/2015/2015 +f 2015/2015/2015 1895/1895/1895 1907/1907/1907 +f 1905/1905/1905 1906/1906/1906 1896/1896/1896 +f 1907/1907/1907 1906/1906/1906 2013/2013/2013 +f 1906/1906/1906 1904/1904/1904 2013/2013/2013 +f 1905/1905/1905 1884/1884/1884 1903/1903/1903 +f 1903/1903/1903 1884/1884/1884 1883/1883/1883 +f 1905/1905/1905 1904/1904/1904 1906/1906/1906 +f 1799/1799/1799 2014/2014/2014 2024/2024/2024 +f 1982/1982/1982 2022/2022/2022 1981/1981/1981 +f 1981/1981/1981 1791/1791/1791 1982/1982/1982 +f 1791/1791/1791 1981/1981/1981 1778/1778/1778 +f 1896/1896/1896 2022/2022/2022 1901/1901/1901 +f 2022/2022/2022 2014/2014/2014 1981/1981/1981 +f 2021/2021/2021 1901/1901/1901 2022/2022/2022 +f 2024/2024/2024 1800/1800/1800 1799/1799/1799 +f 1789/1789/1789 1800/1800/1800 2024/2024/2024 +f 2014/2014/2014 2022/2022/2022 1896/1896/1896 +f 1799/1799/1799 1981/1981/1981 2014/2014/2014 +f 1800/1800/1800 1788/1788/1788 1799/1799/1799 +f 1787/1787/1787 1981/1981/1981 1799/1799/1799 +f 1688/1688/1688 1934/1934/1934 1684/1684/1684 +f 1706/1706/1706 2025/2025/2025 1704/1704/1704 +f 2026/2026/2026 2025/2025/2025 2027/2027/2027 +f 2025/2025/2025 2026/2026/2026 1704/1704/1704 +f 2028/2028/2028 1537/1537/1537 2025/2025/2025 +f 2028/2028/2028 2025/2025/2025 1706/1706/1706 +f 1701/1701/1701 2028/2028/2028 1706/1706/1706 +f 2026/2026/2026 1664/1664/1664 1700/1700/1700 +f 1664/1664/1664 2026/2026/2026 2029/2029/2029 +f 2030/2030/2030 1664/1664/1664 2029/2029/2029 +f 2025/2025/2025 1537/1537/1537 2031/2031/2031 +f 2027/2027/2027 2025/2025/2025 2031/2031/2031 +f 2026/2026/2026 1700/1700/1700 1704/1704/1704 +f 2032/2032/2032 2028/2028/2028 1701/1701/1701 +f 2033/2033/2033 2034/2034/2034 1122/1122/1122 +f 1380/1380/1380 396/396/396 397/397/397 +f 2035/2035/2035 469/469/469 1703/1703/1703 +f 1377/1377/1377 1379/1379/1379 1378/1378/1378 +f 1382/1382/1382 1378/1378/1378 1384/1384/1384 +f 396/396/396 2033/2033/2033 1122/1122/1122 +f 2036/2036/2036 2032/2032/2032 1703/1703/1703 +f 1703/1703/1703 469/469/469 2036/2036/2036 +f 1703/1703/1703 2032/2032/2032 1701/1701/1701 +f 589/589/589 2035/2035/2035 1708/1708/1708 +f 589/589/589 469/469/469 2035/2035/2035 +f 2035/2035/2035 1703/1703/1703 1708/1708/1708 +f 2037/2037/2037 2038/2038/2038 2039/2039/2039 +f 2040/2040/2040 2041/2041/2041 2042/2042/2042 +f 2043/2043/2043 2044/2044/2044 2042/2042/2042 +f 2045/2045/2045 2046/2046/2046 2047/2047/2047 +f 2048/2048/2048 2042/2042/2042 2041/2041/2041 +f 2043/2043/2043 2038/2038/2038 2037/2037/2037 +f 2049/2049/2049 2039/2039/2039 2050/2050/2050 +f 2038/2038/2038 2046/2046/2046 2039/2039/2039 +f 2051/2051/2051 2037/2037/2037 2049/2049/2049 +f 2040/2040/2040 2044/2044/2044 2031/2031/2031 +f 2052/2052/2052 1576/1576/1576 2053/2053/2053 +f 2053/2053/2053 2039/2039/2039 2046/2046/2046 +f 2053/2053/2053 2046/2046/2046 2045/2045/2045 +f 2054/2054/2054 2029/2029/2029 2027/2027/2027 +f 2029/2029/2029 2026/2026/2026 2027/2027/2027 +f 2055/2055/2055 2054/2054/2054 2056/2056/2056 +f 2029/2029/2029 2054/2054/2054 2055/2055/2055 +f 2057/2057/2057 2058/2058/2058 2030/2030/2030 +f 2042/2042/2042 2044/2044/2044 2040/2040/2040 +f 2056/2056/2056 2051/2051/2051 2059/2059/2059 +f 2060/2060/2060 2056/2056/2056 2059/2059/2059 +f 2047/2047/2047 2046/2046/2046 1832/1832/1832 +f 2051/2051/2051 2044/2044/2044 2037/2037/2037 +f 2044/2044/2044 2051/2051/2051 2056/2056/2056 +f 2054/2054/2054 2044/2044/2044 2056/2056/2056 +f 2033/2033/2033 2061/2061/2061 2034/2034/2034 +f 2062/2062/2062 2063/2063/2063 2064/2064/2064 +f 2065/2065/2065 2064/2064/2064 2063/2063/2063 +f 2062/2062/2062 2066/2066/2066 2067/2067/2067 +f 2068/2068/2068 2055/2055/2055 2067/2067/2067 +f 2060/2060/2060 2069/2069/2069 2056/2056/2056 +f 2057/2057/2057 2030/2030/2030 2055/2055/2055 +f 2070/2070/2070 2066/2066/2066 2071/2071/2071 +f 2072/2072/2072 2070/2070/2070 2071/2071/2071 +f 2070/2070/2070 2068/2068/2068 2066/2066/2066 +f 2063/2063/2063 2062/2062/2062 2067/2067/2067 +f 2062/2062/2062 2073/2073/2073 2066/2066/2066 +f 2071/2071/2071 2066/2066/2066 2073/2073/2073 +f 2055/2055/2055 2069/2069/2069 2067/2067/2067 +f 2074/2074/2074 2075/2075/2075 2076/2076/2076 +f 2077/2077/2077 2078/2078/2078 2065/2065/2065 +f 2063/2063/2063 2077/2077/2077 2065/2065/2065 +f 2079/2079/2079 2058/2058/2058 2080/2080/2080 +f 2075/2075/2075 2074/2074/2074 1361/1361/1361 +f 2075/2075/2075 2081/2081/2081 2076/2076/2076 +f 2056/2056/2056 2069/2069/2069 2055/2055/2055 +f 2077/2077/2077 2063/2063/2063 2069/2069/2069 +f 2067/2067/2067 2069/2069/2069 2063/2063/2063 +f 2077/2077/2077 2060/2060/2060 2078/2078/2078 +f 2059/2059/2059 2078/2078/2078 2060/2060/2060 +f 2077/2077/2077 2069/2069/2069 2060/2060/2060 +f 1377/1377/1377 2061/2061/2061 2082/2082/2082 +f 1376/1376/1376 2083/2083/2083 2084/2084/2084 +f 2084/2084/2084 1377/1377/1377 1376/1376/1376 +f 1376/1376/1376 1712/1712/1712 2083/2083/2083 +f 2084/2084/2084 2083/2083/2083 2061/2061/2061 +f 2084/2084/2084 2061/2061/2061 1377/1377/1377 +f 1377/1377/1377 2082/2082/2082 1379/1379/1379 +f 2082/2082/2082 2033/2033/2033 1379/1379/1379 +f 1379/1379/1379 2033/2033/2033 396/396/396 +f 1382/1382/1382 1385/1385/1385 1378/1378/1378 +f 2082/2082/2082 2061/2061/2061 2033/2033/2033 +f 2061/2061/2061 2085/2085/2085 2034/2034/2034 +f 2072/2072/2072 1561/1561/1561 2076/2076/2076 +f 2070/2070/2070 2072/2072/2072 2081/2081/2081 +f 2076/2076/2076 2081/2081/2081 2072/2072/2072 +f 1562/1562/1562 2073/2073/2073 1572/1572/1572 +f 2067/2067/2067 2066/2066/2066 2068/2068/2068 +f 2070/2070/2070 2081/2081/2081 2068/2068/2068 +f 2057/2057/2057 2055/2055/2055 2068/2068/2068 +f 1561/1561/1561 2072/2072/2072 1559/1559/1559 +f 2071/2071/2071 1559/1559/1559 2072/2072/2072 +f 1561/1561/1561 1567/1567/1567 2076/2076/2076 +f 1572/1572/1572 2073/2073/2073 1570/1570/1570 +f 1562/1562/1562 1559/1559/1559 2071/2071/2071 +f 2073/2073/2073 1562/1562/1562 2071/2071/2071 +f 2044/2044/2044 2043/2043/2043 2037/2037/2037 +f 1462/1462/1462 1461/1461/1461 2086/2086/2086 +f 2087/2087/2087 1612/1612/1612 1462/1462/1462 +f 1611/1611/1611 1462/1462/1462 1612/1612/1612 +f 1446/1446/1446 1461/1461/1461 1460/1460/1460 +f 1461/1461/1461 1446/1446/1446 2088/2088/2088 +f 2089/2089/2089 2086/2086/2086 1461/1461/1461 +f 1501/1501/1501 1619/1619/1619 1496/1496/1496 +f 1619/1619/1619 1618/1618/1618 1496/1496/1496 +f 2052/2052/2052 2045/2045/2045 1618/1618/1618 +f 1459/1459/1459 1460/1460/1460 1462/1462/1462 +f 1496/1496/1496 1502/1502/1502 1497/1497/1497 +f 1496/1496/1496 1618/1618/1618 1502/1502/1502 +f 1461/1461/1461 2088/2088/2088 2089/2089/2089 +f 2054/2054/2054 2027/2027/2027 2031/2031/2031 +f 2038/2038/2038 2043/2043/2043 2048/2048/2048 +f 1611/1611/1611 1465/1465/1465 1462/1462/1462 +f 2043/2043/2043 2042/2042/2042 2048/2048/2048 +f 1537/1537/1537 2041/2041/2041 2040/2040/2040 +f 2044/2044/2044 2054/2054/2054 2031/2031/2031 +f 2046/2046/2046 2048/2048/2048 2090/2090/2090 +f 1543/1543/1543 1823/1823/1823 1545/1545/1545 +f 2088/2088/2088 1086/1086/1086 1089/1089/1089 +f 1465/1465/1465 1459/1459/1459 1462/1462/1462 +f 2088/2088/2088 1446/1446/1446 1086/1086/1086 +f 2046/2046/2046 2038/2038/2038 2048/2048/2048 +f 2041/2041/2041 1537/1537/1537 1534/1534/1534 +f 2041/2041/2041 2091/2091/2091 2048/2048/2048 +f 1534/1534/1534 1522/1522/1522 2041/2041/2041 +f 1829/1829/1829 1751/1751/1751 1542/1542/1542 +f 1541/1541/1541 2092/2092/2092 1542/1542/1542 +f 2091/2091/2091 2090/2090/2090 2048/2048/2048 +f 1831/1831/1831 2091/2091/2091 1522/1522/1522 +f 1831/1831/1831 1522/1522/1522 1521/1521/1521 +f 1542/1542/1542 1823/1823/1823 1543/1543/1543 +f 2090/2090/2090 1831/1831/1831 1832/1832/1832 +f 2091/2091/2091 1831/1831/1831 2090/2090/2090 +f 1522/1522/1522 2091/2091/2091 2041/2041/2041 +f 1542/1542/1542 1751/1751/1751 1823/1823/1823 +f 2092/2092/2092 1499/1499/1499 1502/1502/1502 +f 2092/2092/2092 1541/1541/1541 1499/1499/1499 +f 2047/2047/2047 1542/1542/1542 2093/2093/2093 +f 2094/2094/2094 2092/2092/2092 1502/1502/1502 +f 2093/2093/2093 2092/2092/2092 2094/2094/2094 +f 2093/2093/2093 2094/2094/2094 2047/2047/2047 +f 1542/1542/1542 2092/2092/2092 2093/2093/2093 +f 1832/1832/1832 1542/1542/1542 2047/2047/2047 +f 1542/1542/1542 1832/1832/1832 1829/1829/1829 +f 2090/2090/2090 1832/1832/1832 2046/2046/2046 +f 2094/2094/2094 2045/2045/2045 2047/2047/2047 +f 1502/1502/1502 1618/1618/1618 2094/2094/2094 +f 2031/2031/2031 1537/1537/1537 2040/2040/2040 +f 2073/2073/2073 2064/2064/2064 1570/1570/1570 +f 2095/2095/2095 1713/1713/1713 1603/1603/1603 +f 2083/2083/2083 1712/1712/1712 2096/2096/2096 +f 2065/2065/2065 2050/2050/2050 2064/2064/2064 +f 2050/2050/2050 1575/1575/1575 1570/1570/1570 +f 2062/2062/2062 2064/2064/2064 2073/2073/2073 +f 2095/2095/2095 2087/2087/2087 2096/2096/2096 +f 2096/2096/2096 2087/2087/2087 2085/2085/2085 +f 2096/2096/2096 1713/1713/1713 2095/2095/2095 +f 2096/2096/2096 1712/1712/1712 1713/1713/1713 +f 2095/2095/2095 1612/1612/1612 2087/2087/2087 +f 1612/1612/1612 2095/2095/2095 1603/1603/1603 +f 2064/2064/2064 2050/2050/2050 1570/1570/1570 +f 2045/2045/2045 2094/2094/2094 1618/1618/1618 +f 2053/2053/2053 1576/1576/1576 2050/2050/2050 +f 2039/2039/2039 2053/2053/2053 2050/2050/2050 +f 2037/2037/2037 2039/2039/2039 2049/2049/2049 +f 2059/2059/2059 2051/2051/2051 2049/2049/2049 +f 2053/2053/2053 2045/2045/2045 2052/2052/2052 +f 1576/1576/1576 2052/2052/2052 1573/1573/1573 +f 1573/1573/1573 2052/2052/2052 1618/1618/1618 +f 2050/2050/2050 1576/1576/1576 1575/1575/1575 +f 2050/2050/2050 2078/2078/2078 2059/2059/2059 +f 2049/2049/2049 2050/2050/2050 2059/2059/2059 +f 2065/2065/2065 2078/2078/2078 2050/2050/2050 +f 1122/1122/1122 2097/2097/2097 1089/1089/1089 +f 2036/2036/2036 469/469/469 1535/1535/1535 +f 2036/2036/2036 1535/1535/1535 1536/1536/1536 +f 2098/2098/2098 1089/1089/1089 2097/2097/2097 +f 2099/2099/2099 2098/2098/2098 2097/2097/2097 +f 2034/2034/2034 2097/2097/2097 1122/1122/1122 +f 1537/1537/1537 1536/1536/1536 1520/1520/1520 +f 1518/1518/1518 1510/1510/1510 1536/1536/1536 +f 1536/1536/1536 1537/1537/1537 2028/2028/2028 +f 2032/2032/2032 2036/2036/2036 1536/1536/1536 +f 1536/1536/1536 1510/1510/1510 1520/1520/1520 +f 2028/2028/2028 2032/2032/2032 1536/1536/1536 +f 2089/2089/2089 2088/2088/2088 2099/2099/2099 +f 2100/2100/2100 2087/2087/2087 2086/2086/2086 +f 2086/2086/2086 2087/2087/2087 1462/1462/1462 +f 2100/2100/2100 2099/2099/2099 2085/2085/2085 +f 2096/2096/2096 2085/2085/2085 2083/2083/2083 +f 2100/2100/2100 2086/2086/2086 2089/2089/2089 +f 2099/2099/2099 2100/2100/2100 2089/2089/2089 +f 2061/2061/2061 2083/2083/2083 2085/2085/2085 +f 2098/2098/2098 2088/2088/2088 1089/1089/1089 +f 2098/2098/2098 2099/2099/2099 2088/2088/2088 +f 2085/2085/2085 2099/2099/2099 2034/2034/2034 +f 2034/2034/2034 2099/2099/2099 2097/2097/2097 +f 2087/2087/2087 2100/2100/2100 2085/2085/2085 +f 2075/2075/2075 1361/1361/1361 2080/2080/2080 +f 2101/2101/2101 1423/1423/1423 1857/1857/1857 +f 2102/2102/2102 2101/2101/2101 1857/1857/1857 +f 1857/1857/1857 1423/1423/1423 2103/2103/2103 +f 1912/1912/1912 1915/1915/1915 2104/2104/2104 +f 1424/1424/1424 1423/1423/1423 2101/2101/2101 +f 1472/1472/1472 1424/1424/1424 2101/2101/2101 +f 2105/2105/2105 2106/2106/2106 2107/2107/2107 +f 1422/1422/1422 2108/2108/2108 1423/1423/1423 +f 2103/2103/2103 1423/1423/1423 2108/2108/2108 +f 1855/1855/1855 2104/2104/2104 2102/2102/2102 +f 1857/1857/1857 1855/1855/1855 2102/2102/2102 +f 1912/1912/1912 2104/2104/2104 1855/1855/1855 +f 2109/2109/2109 2104/2104/2104 1915/1915/1915 +f 1472/1472/1472 2101/2101/2101 1479/1479/1479 +f 2110/2110/2110 1478/1478/1478 1479/1479/1479 +f 1479/1479/1479 1478/1478/1478 1471/1471/1471 +f 2111/2111/2111 1887/1887/1887 1893/1893/1893 +f 2111/2111/2111 2112/2112/2112 1887/1887/1887 +f 2110/2110/2110 1479/1479/1479 2101/2101/2101 +f 2109/2109/2109 2112/2112/2112 2110/2110/2110 +f 2109/2109/2109 1915/1915/1915 1887/1887/1887 +f 2112/2112/2112 2109/2109/2109 1887/1887/1887 +f 2110/2110/2110 2101/2101/2101 2102/2102/2102 +f 2109/2109/2109 2110/2110/2110 2102/2102/2102 +f 2102/2102/2102 2104/2104/2104 2109/2109/2109 +f 1428/1428/1428 1429/1429/1429 1342/1342/1342 +f 2113/2113/2113 2114/2114/2114 2115/2115/2115 +f 1843/1843/1843 2115/2115/2115 1842/1842/1842 +f 1856/1856/1856 2116/2116/2116 1833/1833/1833 +f 1428/1428/1428 2113/2113/2113 2106/2106/2106 +f 2106/2106/2106 1429/1429/1429 1428/1428/1428 +f 1842/1842/1842 2114/2114/2114 1875/1875/1875 +f 1876/1876/1876 1875/1875/1875 2114/2114/2114 +f 1875/1875/1875 1846/1846/1846 1842/1842/1842 +f 1847/1847/1847 2107/2107/2107 1843/1843/1843 +f 1834/1834/1834 1847/1847/1847 1843/1843/1843 +f 1842/1842/1842 2115/2115/2115 2114/2114/2114 +f 2108/2108/2108 2105/2105/2105 2107/2107/2107 +f 2116/2116/2116 1857/1857/1857 2103/2103/2103 +f 2108/2108/2108 2116/2116/2116 2103/2103/2103 +f 2116/2116/2116 1856/1856/1856 1857/1857/1857 +f 1847/1847/1847 1833/1833/1833 2107/2107/2107 +f 2116/2116/2116 2108/2108/2108 1833/1833/1833 +f 1833/1833/1833 2108/2108/2108 2107/2107/2107 +f 2106/2106/2106 2115/2115/2115 2107/2107/2107 +f 1843/1843/1843 2107/2107/2107 2115/2115/2115 +f 1422/1422/1422 2105/2105/2105 2108/2108/2108 +f 1429/1429/1429 2106/2106/2106 2105/2105/2105 +f 2106/2106/2106 2113/2113/2113 2115/2115/2115 +f 2105/2105/2105 1422/1422/1422 1429/1429/1429 +f 1893/1893/1893 2117/2117/2117 2118/2118/2118 +f 1482/1482/1482 2119/2119/2119 1965/1965/1965 +f 2119/2119/2119 1951/1951/1951 1965/1965/1965 +f 1484/1484/1484 1965/1965/1965 1964/1964/1964 +f 1483/1483/1483 2119/2119/2119 1482/1482/1482 +f 1482/1482/1482 1484/1484/1484 1452/1452/1452 +f 1450/1450/1450 1449/1449/1449 1484/1484/1484 +f 1952/1952/1952 2120/2120/2120 1475/1475/1475 +f 2120/2120/2120 2121/2121/2121 1475/1475/1475 +f 1952/1952/1952 1951/1951/1951 2120/2120/2120 +f 1480/1480/1480 2119/2119/2119 1483/1483/1483 +f 1480/1480/1480 2120/2120/2120 2119/2119/2119 +f 1480/1480/1480 2121/2121/2121 2120/2120/2120 +f 1450/1450/1450 1963/1963/1963 939/939/939 +f 1692/1692/1692 2004/2004/2004 1685/1685/1685 +f 1686/1686/1686 1685/1685/1685 2004/2004/2004 +f 2004/2004/2004 1692/1692/1692 2003/2003/2003 +f 1934/1934/1934 1939/1939/1939 1684/1684/1684 +f 1695/1695/1695 1940/1940/1940 1696/1696/1696 +f 1939/1939/1939 1695/1695/1695 1693/1693/1693 +f 939/939/939 940/940/940 1450/1450/1450 +f 1963/1963/1963 1450/1450/1450 1964/1964/1964 +f 1484/1484/1484 1964/1964/1964 1450/1450/1450 +f 650/650/650 941/941/941 1692/1692/1692 +f 2003/2003/2003 1692/1692/1692 941/941/941 +f 1484/1484/1484 1482/1482/1482 1965/1965/1965 +f 1888/1888/1888 1858/1858/1858 1860/1860/1860 +f 2122/2122/2122 1478/1478/1478 2110/2110/2110 +f 1478/1478/1478 2117/2117/2117 1476/1476/1476 +f 1942/1942/1942 1944/1944/1944 1872/1872/1872 +f 2111/2111/2111 1893/1893/1893 2118/2118/2118 +f 1893/1893/1893 1888/1888/1888 1860/1860/1860 +f 2111/2111/2111 2118/2118/2118 2112/2112/2112 +f 2110/2110/2110 2112/2112/2112 2118/2118/2118 +f 1953/1953/1953 2117/2117/2117 1893/1893/1893 +f 2117/2117/2117 1474/1474/1474 1476/1476/1476 +f 2122/2122/2122 2118/2118/2118 2117/2117/2117 +f 2118/2118/2118 2122/2122/2122 2110/2110/2110 +f 2122/2122/2122 2117/2117/2117 1478/1478/1478 +f 1872/1872/1872 1944/1944/1944 1945/1945/1945 +f 1944/1944/1944 1952/1952/1952 1475/1475/1475 +f 1475/1475/1475 1953/1953/1953 1945/1945/1945 +f 2119/2119/2119 2120/2120/2120 1951/1951/1951 +f 1475/1475/1475 2121/2121/2121 1476/1476/1476 +f 2121/2121/2121 1480/1480/1480 1476/1476/1476 +f 1860/1860/1860 1859/1859/1859 1870/1870/1870 +f 1859/1859/1859 1866/1866/1866 1870/1870/1870 +f 1953/1953/1953 1474/1474/1474 2117/2117/2117 +f 1945/1945/1945 1953/1953/1953 1956/1956/1956 +f 1860/1860/1860 1956/1956/1956 1893/1893/1893 +f 1956/1956/1956 1953/1953/1953 1893/1893/1893 +f 1874/1874/1874 1876/1876/1876 1863/1863/1863 +f 2079/2079/2079 2123/2123/2123 2058/2058/2058 +f 1660/1660/1660 2123/2123/2123 2079/2079/2079 +f 1661/1661/1661 1660/1660/1660 2079/2079/2079 +f 1361/1361/1361 2079/2079/2079 2080/2080/2080 +f 1661/1661/1661 2079/2079/2079 1361/1361/1361 +f 1661/1661/1661 1361/1361/1361 246/246/246 +f 1664/1664/1664 2123/2123/2123 1655/1655/1655 +f 2074/2074/2074 1566/1566/1566 1361/1361/1361 +f 1596/1596/1596 247/247/247 2124/2124/2124 +f 2030/2030/2030 2123/2123/2123 1664/1664/1664 +f 2058/2058/2058 2123/2123/2123 2030/2030/2030 +f 2123/2123/2123 1660/1660/1660 1655/1655/1655 +f 2055/2055/2055 2030/2030/2030 2029/2029/2029 +f 2125/2125/2125 1430/1430/1430 1433/1433/1433 +f 1433/1433/1433 2126/2126/2126 2127/2127/2127 +f 2125/2125/2125 1433/1433/1433 2127/2127/2127 +f 1936/1936/1936 1938/1938/1938 2128/2128/2128 +f 2129/2129/2129 2127/2127/2127 1936/1936/1936 +f 1937/1937/1937 1936/1936/1936 2127/2127/2127 +f 2080/2080/2080 2057/2057/2057 2081/2081/2081 +f 2075/2075/2075 2080/2080/2080 2081/2081/2081 +f 2080/2080/2080 2058/2058/2058 2057/2057/2057 +f 1433/1433/1433 2130/2130/2130 2126/2126/2126 +f 2131/2131/2131 2126/2126/2126 2130/2130/2130 +f 2081/2081/2081 2057/2057/2057 2068/2068/2068 +f 1696/1696/1696 2132/2132/2132 2133/2133/2133 +f 2130/2130/2130 2132/2132/2132 2131/2131/2131 +f 2130/2130/2130 1433/1433/1433 1432/1432/1432 +f 2133/2133/2133 1441/1441/1441 1235/1235/1235 +f 1696/1696/1696 1940/1940/1940 2131/2131/2131 +f 2132/2132/2132 1696/1696/1696 2131/2131/2131 +f 2126/2126/2126 2131/2131/2131 1940/1940/1940 +f 2127/2127/2127 2126/2126/2126 1937/1937/1937 +f 2126/2126/2126 1940/1940/1940 1937/1937/1937 +f 2134/2134/2134 2132/2132/2132 2130/2130/2130 +f 2133/2133/2133 2134/2134/2134 1441/1441/1441 +f 1432/1432/1432 2134/2134/2134 2130/2130/2130 +f 1235/1235/1235 1441/1441/1441 1153/1153/1153 +f 1566/1566/1566 2074/2074/2074 1567/1567/1567 +f 1566/1566/1566 1569/1569/1569 2124/2124/2124 +f 1596/1596/1596 2124/2124/2124 1569/1569/1569 +f 2124/2124/2124 247/247/247 1361/1361/1361 +f 1566/1566/1566 2124/2124/2124 1361/1361/1361 +f 2076/2076/2076 1567/1567/1567 2074/2074/2074 +f 1236/1236/1236 2133/2133/2133 1235/1235/1235 +f 1441/1441/1441 1432/1432/1432 1439/1439/1439 +f 2134/2134/2134 1432/1432/1432 1441/1441/1441 +f 1236/1236/1236 672/672/672 1696/1696/1696 +f 2132/2132/2132 2134/2134/2134 2133/2133/2133 +f 1696/1696/1696 2133/2133/2133 1236/1236/1236 +f 2129/2129/2129 1936/1936/1936 2128/2128/2128 +f 2135/2135/2135 2136/2136/2136 2137/2137/2137 +f 2138/2138/2138 2139/2139/2139 2136/2136/2136 +f 2136/2136/2136 2135/2135/2135 1946/1946/1946 +f 1427/1427/1427 2139/2139/2139 1425/1425/1425 +f 2139/2139/2139 2138/2138/2138 1425/1425/1425 +f 1425/1425/1425 2138/2138/2138 1428/1428/1428 +f 2137/2137/2137 2139/2139/2139 1421/1421/1421 +f 2140/2140/2140 2141/2141/2141 2142/2142/2142 +f 2141/2141/2141 2137/2137/2137 2142/2142/2142 +f 1949/1949/1949 2136/2136/2136 1946/1946/1946 +f 1946/1946/1946 2135/2135/2135 1948/1948/1948 +f 2142/2142/2142 2137/2137/2137 1421/1421/1421 +f 1955/1955/1955 2136/2136/2136 1949/1949/1949 +f 2114/2114/2114 2113/2113/2113 1876/1876/1876 +f 2143/2143/2143 2113/2113/2113 2138/2138/2138 +f 1876/1876/1876 2113/2113/2113 2143/2143/2143 +f 1863/1863/1863 1876/1876/1876 2144/2144/2144 +f 1861/1861/1861 1863/1863/1863 2144/2144/2144 +f 1428/1428/1428 1426/1426/1426 1425/1425/1425 +f 2143/2143/2143 2136/2136/2136 1955/1955/1955 +f 1861/1861/1861 2143/2143/2143 1955/1955/1955 +f 2138/2138/2138 2136/2136/2136 2143/2143/2143 +f 2113/2113/2113 1428/1428/1428 2138/2138/2138 +f 2144/2144/2144 2143/2143/2143 1861/1861/1861 +f 1876/1876/1876 2143/2143/2143 2144/2144/2144 +f 2145/2145/2145 2146/2146/2146 1412/1412/1412 +f 2147/2147/2147 1412/1412/1412 2146/2146/2146 +f 2145/2145/2145 1938/1938/1938 1926/1926/1926 +f 1413/1413/1413 1412/1412/1412 2147/2147/2147 +f 2145/2145/2145 1412/1412/1412 2128/2128/2128 +f 1412/1412/1412 1408/1408/1408 2128/2128/2128 +f 1430/1430/1430 2125/2125/2125 2129/2129/2129 +f 2129/2129/2129 2125/2125/2125 2127/2127/2127 +f 2128/2128/2128 1408/1408/1408 2129/2129/2129 +f 2146/2146/2146 2145/2145/2145 1926/1926/1926 +f 2145/2145/2145 2128/2128/2128 1938/1938/1938 +f 1408/1408/1408 1430/1430/1430 2129/2129/2129 +f 1926/1926/1926 1922/1922/1922 2146/2146/2146 +f 1923/1923/1923 1948/1948/1948 2141/2141/2141 +f 2147/2147/2147 1421/1421/1421 1413/1413/1413 +f 2139/2139/2139 1427/1427/1427 1421/1421/1421 +f 2136/2136/2136 2139/2139/2139 2137/2137/2137 +f 1948/1948/1948 2135/2135/2135 2141/2141/2141 +f 2135/2135/2135 2137/2137/2137 2141/2141/2141 +f 2141/2141/2141 2140/2140/2140 1923/1923/1923 +f 2140/2140/2140 1922/1922/1922 1923/1923/1923 +f 2140/2140/2140 2146/2146/2146 1922/1922/1922 +f 2142/2142/2142 1421/1421/1421 2147/2147/2147 +f 2140/2140/2140 2142/2142/2142 2146/2146/2146 +f 2147/2147/2147 2146/2146/2146 2142/2142/2142 +v 0.575857 0.754684 0.664706 +v 0.563969 0.752566 0.660989 +v 0.566988 0.753485 0.661960 +v 0.592506 0.756463 0.668785 +v 0.592547 0.756901 0.668733 +v 0.575695 0.754423 0.665060 +v 0.566863 0.752954 0.662267 +v 0.575869 0.755136 0.664651 +v 0.563784 0.753220 0.661232 +v 0.575675 0.755543 0.665029 +v 0.592233 0.757454 0.669598 +v 0.610167 0.755699 0.671122 +v 0.609983 0.756216 0.671950 +v 0.592047 0.756761 0.669990 +v 0.592361 0.756209 0.669124 +v 0.628677 0.754046 0.671507 +v 0.610051 0.756634 0.671901 +v 0.628472 0.753416 0.671863 +v 0.628533 0.752945 0.671081 +v 0.575423 0.755712 0.665543 +v 0.566615 0.753916 0.662628 +v 0.566489 0.753384 0.662935 +v 0.563618 0.752497 0.661652 +v 0.575249 0.754998 0.665952 +v 0.592088 0.757200 0.669938 +v 0.655542 0.726471 0.694164 +v 0.667944 0.719668 0.693110 +v 0.655280 0.725966 0.694466 +v 0.670745 0.717816 0.692778 +v 0.670771 0.718014 0.693173 +v 0.575261 0.755451 0.665896 +v 0.563432 0.753152 0.661896 +v 0.647073 0.748616 0.668679 +v 0.647123 0.749036 0.669408 +v 0.663502 0.742739 0.665498 +v 0.664095 0.742072 0.664944 +v 0.646864 0.748028 0.669016 +v 0.628738 0.753573 0.670725 +v 0.646913 0.748447 0.669746 +v 0.663452 0.742630 0.666116 +v 0.676043 0.736224 0.661616 +v 0.678739 0.734709 0.660214 +v 0.678623 0.734411 0.660388 +v 0.664022 0.741913 0.665843 +v 0.683910 0.731271 0.657709 +v 0.663908 0.741578 0.665230 +v 0.610180 0.756881 0.671576 +v 0.610363 0.756362 0.670749 +v 0.560716 0.739566 0.667127 +v 0.571086 0.741645 0.673692 +v 0.563153 0.739959 0.669139 +v 0.570855 0.741394 0.674048 +v 0.585733 0.742999 0.681992 +v 0.585948 0.743247 0.681646 +v 0.571129 0.742100 0.673609 +v 0.563353 0.740484 0.668809 +v 0.586015 0.743690 0.681574 +v 0.570894 0.742523 0.673948 +v 0.601977 0.743087 0.688781 +v 0.585356 0.744025 0.682739 +v 0.585289 0.743582 0.682812 +v 0.619686 0.739710 0.692876 +v 0.601886 0.742662 0.688846 +v 0.602176 0.743330 0.688448 +v 0.585572 0.744274 0.682393 +v 0.619572 0.739310 0.692935 +v 0.602206 0.742120 0.688042 +v 0.619771 0.738820 0.692154 +v 0.570334 0.742459 0.674789 +v 0.570291 0.742003 0.674871 +v 0.562698 0.740416 0.669748 +v 0.560074 0.740188 0.667949 +v 0.560261 0.739521 0.667764 +v 0.570566 0.742711 0.674432 +v 0.562899 0.740942 0.669418 +v 0.560530 0.740234 0.667313 +v 0.637883 0.733202 0.694275 +v 0.638179 0.733800 0.693919 +v 0.638094 0.734231 0.694665 +v 0.654862 0.727180 0.694562 +v 0.620065 0.739455 0.691777 +v 0.654681 0.727066 0.695209 +v 0.619867 0.739947 0.692557 +v 0.667982 0.719986 0.693741 +v 0.655280 0.726305 0.695106 +v 0.637798 0.733632 0.695022 +v 0.602496 0.742786 0.687644 +v 0.578259 0.736520 0.635397 +v 0.578368 0.736933 0.635390 +v 0.595019 0.731152 0.631880 +v 0.578293 0.737395 0.636318 +v 0.568892 0.739645 0.636932 +v 0.565516 0.740281 0.637409 +v 0.595063 0.731557 0.632746 +v 0.565552 0.740881 0.637727 +v 0.568793 0.740004 0.637637 +v 0.578159 0.737134 0.636634 +v 0.594946 0.731308 0.633045 +v 0.594815 0.730925 0.633054 +v 0.594772 0.730522 0.632187 +v 0.610684 0.723125 0.626573 +v 0.625594 0.714564 0.619683 +v 0.610826 0.723467 0.627372 +v 0.625841 0.715097 0.619404 +v 0.625373 0.714282 0.618958 +v 0.568715 0.739133 0.637175 +v 0.578126 0.736260 0.635712 +v 0.657715 0.691281 0.651592 +v 0.663355 0.684591 0.648221 +v 0.659620 0.689042 0.650961 +v 0.649241 0.700643 0.655504 +v 0.648928 0.700242 0.655765 +v 0.568616 0.739491 0.637880 +v 0.648879 0.701412 0.656079 +v 0.659810 0.689283 0.650803 +v 0.657873 0.691475 0.652226 +v 0.578051 0.736720 0.636641 +v 0.565351 0.740779 0.638377 +v 0.565316 0.740179 0.638059 +v 0.611077 0.724052 0.627078 +v 0.625620 0.714814 0.618680 +v 0.638656 0.704687 0.609154 +v 0.638417 0.704208 0.609417 +v 0.649366 0.694108 0.598389 +v 0.649163 0.693719 0.598610 +v 0.638933 0.704910 0.609801 +v 0.649182 0.694784 0.599196 +v 0.649230 0.694626 0.599710 +v 0.657471 0.683870 0.587386 +v 0.656137 0.685818 0.589903 +v 0.657349 0.683642 0.587519 +v 0.649436 0.693879 0.599136 +v 0.638694 0.704429 0.610065 +v 0.610933 0.723708 0.626280 +v 0.591502 0.739187 0.657384 +v 0.576664 0.744190 0.652676 +v 0.591660 0.739580 0.657345 +v 0.576801 0.744609 0.652630 +v 0.568666 0.746733 0.649617 +v 0.565797 0.747138 0.648536 +v 0.576483 0.745219 0.653521 +v 0.565785 0.747791 0.648785 +v 0.568390 0.747206 0.650281 +v 0.591460 0.740122 0.658219 +v 0.591076 0.739516 0.658589 +v 0.591277 0.738975 0.657714 +v 0.606505 0.731761 0.660358 +v 0.621599 0.722982 0.661715 +v 0.606415 0.732226 0.661205 +v 0.621974 0.723513 0.661384 +v 0.621590 0.722597 0.660906 +v 0.568385 0.746257 0.649910 +v 0.576420 0.743974 0.653019 +v 0.576238 0.745003 0.653865 +v 0.591234 0.739909 0.658549 +v 0.568108 0.746728 0.650575 +v 0.675894 0.735906 0.661017 +v 0.565406 0.747139 0.649187 +v 0.576100 0.744583 0.653911 +v 0.565394 0.747792 0.649437 +v 0.606591 0.732590 0.661171 +v 0.636395 0.712252 0.658986 +v 0.636488 0.712558 0.659748 +v 0.621964 0.723126 0.660576 +v 0.636031 0.711766 0.659296 +v 0.636124 0.712071 0.660058 +v 0.648756 0.701286 0.656703 +v 0.649062 0.700460 0.656411 +v 0.606797 0.732798 0.660855 +v 0.606886 0.732331 0.660009 +v 0.437949 0.752566 0.660989 +v 0.426061 0.754684 0.664706 +v 0.434930 0.753485 0.661960 +v 0.409412 0.756463 0.668785 +v 0.409371 0.756901 0.668733 +v 0.426223 0.754423 0.665060 +v 0.435055 0.752954 0.662267 +v 0.426049 0.755136 0.664651 +v 0.426243 0.755543 0.665029 +v 0.438134 0.753220 0.661232 +v 0.409685 0.757454 0.669598 +v 0.391935 0.756216 0.671950 +v 0.391751 0.755699 0.671122 +v 0.409871 0.756761 0.669990 +v 0.409557 0.756209 0.669124 +v 0.391867 0.756634 0.671901 +v 0.373241 0.754046 0.671507 +v 0.373446 0.753416 0.671863 +v 0.373385 0.752945 0.671081 +v 0.426495 0.755712 0.665543 +v 0.435303 0.753916 0.662628 +v 0.435429 0.753384 0.662935 +v 0.438300 0.752497 0.661652 +v 0.426669 0.754998 0.665952 +v 0.409830 0.757200 0.669938 +v 0.333974 0.719668 0.693110 +v 0.346376 0.726471 0.694164 +v 0.346638 0.725966 0.694466 +v 0.331173 0.717816 0.692778 +v 0.331147 0.718014 0.693173 +v 0.426657 0.755451 0.665896 +v 0.438486 0.753152 0.661896 +v 0.354795 0.749036 0.669408 +v 0.354845 0.748616 0.668679 +v 0.338416 0.742739 0.665498 +v 0.337823 0.742072 0.664944 +v 0.355054 0.748028 0.669016 +v 0.373180 0.753573 0.670725 +v 0.355005 0.748447 0.669746 +v 0.338466 0.742630 0.666116 +v 0.323179 0.734709 0.660214 +v 0.325875 0.736224 0.661616 +v 0.323295 0.734411 0.660388 +v 0.337896 0.741913 0.665843 +v 0.318008 0.731271 0.657709 +v 0.338010 0.741578 0.665230 +v 0.391738 0.756881 0.671576 +v 0.391555 0.756362 0.670749 +v 0.430832 0.741645 0.673692 +v 0.441202 0.739566 0.667127 +v 0.438765 0.739959 0.669139 +v 0.431063 0.741394 0.674048 +v 0.416185 0.742999 0.681992 +v 0.415970 0.743247 0.681646 +v 0.430789 0.742100 0.673609 +v 0.438565 0.740484 0.668809 +v 0.415903 0.743690 0.681574 +v 0.431024 0.742523 0.673948 +v 0.416562 0.744025 0.682739 +v 0.399941 0.743087 0.688781 +v 0.416629 0.743582 0.682812 +v 0.382232 0.739710 0.692876 +v 0.400032 0.742662 0.688846 +v 0.399742 0.743330 0.688448 +v 0.416346 0.744274 0.682393 +v 0.382346 0.739310 0.692935 +v 0.399712 0.742120 0.688042 +v 0.382147 0.738820 0.692154 +v 0.431584 0.742459 0.674789 +v 0.431627 0.742003 0.674871 +v 0.439220 0.740416 0.669748 +v 0.441844 0.740188 0.667949 +v 0.441657 0.739521 0.667764 +v 0.431352 0.742711 0.674432 +v 0.439019 0.740942 0.669418 +v 0.441388 0.740234 0.667313 +v 0.364035 0.733202 0.694275 +v 0.363739 0.733800 0.693919 +v 0.363824 0.734231 0.694665 +v 0.347056 0.727180 0.694562 +v 0.381853 0.739455 0.691777 +v 0.347237 0.727066 0.695209 +v 0.382051 0.739947 0.692557 +v 0.333936 0.719986 0.693741 +v 0.346638 0.726305 0.695106 +v 0.364120 0.733632 0.695022 +v 0.399422 0.742786 0.687644 +v 0.423550 0.736933 0.635390 +v 0.423659 0.736520 0.635397 +v 0.406899 0.731152 0.631880 +v 0.423625 0.737395 0.636318 +v 0.433026 0.739645 0.636932 +v 0.436402 0.740281 0.637409 +v 0.406855 0.731557 0.632746 +v 0.436366 0.740881 0.637727 +v 0.433125 0.740004 0.637637 +v 0.423759 0.737134 0.636634 +v 0.406972 0.731308 0.633045 +v 0.407146 0.730522 0.632187 +v 0.407103 0.730925 0.633054 +v 0.391234 0.723125 0.626573 +v 0.391092 0.723467 0.627372 +v 0.376324 0.714564 0.619683 +v 0.376077 0.715097 0.619404 +v 0.376545 0.714282 0.618958 +v 0.433203 0.739133 0.637175 +v 0.423792 0.736260 0.635712 +v 0.338563 0.684591 0.648221 +v 0.344203 0.691281 0.651592 +v 0.342298 0.689042 0.650961 +v 0.352677 0.700643 0.655504 +v 0.352990 0.700242 0.655765 +v 0.433302 0.739491 0.637880 +v 0.353039 0.701412 0.656079 +v 0.344045 0.691475 0.652226 +v 0.342108 0.689283 0.650803 +v 0.423867 0.736720 0.636641 +v 0.436567 0.740779 0.638377 +v 0.436602 0.740179 0.638059 +v 0.390841 0.724052 0.627078 +v 0.363262 0.704687 0.609154 +v 0.376298 0.714814 0.618680 +v 0.363501 0.704208 0.609417 +v 0.352552 0.694108 0.598389 +v 0.352755 0.693719 0.598610 +v 0.362985 0.704910 0.609801 +v 0.352736 0.694784 0.599196 +v 0.352688 0.694626 0.599710 +v 0.344447 0.683870 0.587386 +v 0.345781 0.685818 0.589903 +v 0.344569 0.683642 0.587519 +v 0.352482 0.693879 0.599136 +v 0.363224 0.704429 0.610065 +v 0.390985 0.723708 0.626280 +v 0.425254 0.744190 0.652676 +v 0.410416 0.739187 0.657384 +v 0.410258 0.739580 0.657345 +v 0.425117 0.744609 0.652630 +v 0.433252 0.746733 0.649617 +v 0.436121 0.747138 0.648536 +v 0.425435 0.745219 0.653521 +v 0.436133 0.747791 0.648785 +v 0.433528 0.747206 0.650281 +v 0.410458 0.740122 0.658219 +v 0.410641 0.738975 0.657714 +v 0.410842 0.739516 0.658589 +v 0.395413 0.731761 0.660358 +v 0.395503 0.732226 0.661205 +v 0.380319 0.722982 0.661715 +v 0.379944 0.723513 0.661384 +v 0.380328 0.722597 0.660906 +v 0.433533 0.746257 0.649910 +v 0.425498 0.743974 0.653019 +v 0.425680 0.745003 0.653865 +v 0.410684 0.739909 0.658549 +v 0.433810 0.746728 0.650575 +v 0.326024 0.735906 0.661017 +v 0.436512 0.747139 0.649187 +v 0.425818 0.744583 0.653911 +v 0.436524 0.747792 0.649437 +v 0.395327 0.732590 0.661171 +v 0.365523 0.712252 0.658986 +v 0.365430 0.712558 0.659748 +v 0.379954 0.723126 0.660576 +v 0.365887 0.711766 0.659296 +v 0.365794 0.712071 0.660058 +v 0.353162 0.701286 0.656703 +v 0.352856 0.700460 0.656411 +v 0.395121 0.732798 0.660855 +v 0.395032 0.732331 0.660009 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vn 0.2912 -0.5230 -0.8010 +vn 0.3373 -0.5401 -0.7711 +vn 0.2152 0.3645 -0.9059 +vn 0.1657 -0.5139 -0.8417 +vn 0.1409 0.4553 -0.8791 +vn 0.2230 -0.8729 -0.4339 +vn 0.1412 -0.9821 0.1248 +vn 0.2022 0.3329 -0.9210 +vn 0.0064 0.8439 -0.5365 +vn 0.0211 0.8485 -0.5287 +vn -0.0340 0.9983 0.0466 +vn -0.0663 -0.9691 -0.2376 +vn -0.0806 -0.4100 0.9085 +vn -0.1438 -0.4010 0.9047 +vn 0.0450 -0.9990 0.0016 +vn 0.2161 0.9332 0.2872 +vn -0.0006 0.4970 0.8677 +vn 0.0023 -0.2502 0.9682 +vn -0.2092 -0.9437 -0.2562 +vn -0.1741 0.9799 0.0977 +vn -0.2107 0.9761 0.0521 +vn -0.1911 -0.4754 0.8587 +vn 0.0143 -0.8371 0.5469 +vn -0.2123 -0.3723 0.9035 +vn -0.1679 0.5257 0.8339 +vn 0.0608 0.1881 -0.9803 +vn 0.2234 0.5108 -0.8301 +vn -0.4147 -0.8600 -0.2971 +vn 0.6380 -0.5984 -0.4846 +vn 0.8561 -0.2004 0.4763 +vn -0.3105 0.5283 0.7902 +vn -0.3626 0.5198 0.7735 +vn -0.0513 0.3306 -0.9424 +vn 0.3341 0.8992 0.2824 +vn 0.3345 0.8986 -0.2838 +vn -0.1528 0.2390 -0.9589 +vn -0.3336 -0.9073 -0.2560 +vn 0.0103 0.3071 -0.9516 +vn 0.0632 -0.2832 0.9570 +vn 0.4047 0.4406 0.8013 +vn 0.5197 0.4942 0.6968 +vn 0.5604 0.8278 0.0251 +vn 0.2127 -0.3999 0.8915 +vn 0.0196 -0.5568 0.8304 +vn 0.8026 -0.4733 -0.3629 +vn -0.4433 -0.8629 -0.2423 +vn 0.0927 0.9923 0.0820 +vn 0.0796 0.2860 -0.9549 +vn 0.5116 -0.5952 -0.6196 +vn 0.4709 -0.5777 -0.6666 +vn 0.0887 -0.9793 0.1819 +vn 0.4198 -0.6875 -0.5926 +vn 0.0129 -0.9991 0.0390 +vn 0.3460 -0.5724 -0.7434 +vn 0.4412 0.2902 -0.8491 +vn 0.4534 0.3313 -0.8274 +vn 0.3641 0.4206 -0.8310 +vn 0.1610 0.8441 -0.5114 +vn -0.1752 0.5577 0.8113 +vn -0.3425 0.5808 0.7385 +vn -0.3735 -0.3576 0.8559 +vn -0.0222 0.5172 0.8556 +vn -0.3059 -0.3671 0.8784 +vn 0.1060 0.9916 0.0732 +vn -0.0188 0.9997 0.0117 +vn -0.2483 -0.3821 0.8901 +vn -0.0494 -0.9766 -0.2091 +vn -0.1889 -0.9468 -0.2604 +vn -0.4849 0.5793 0.6552 +vn -0.4478 -0.3357 0.8287 +vn -0.4284 -0.4289 0.7953 +vn -0.5366 0.5806 0.6123 +vn -0.1267 -0.8365 0.5330 +vn -0.1767 0.9838 0.0290 +vn -0.2127 0.9770 -0.0111 +vn 0.1493 0.8393 -0.5228 +vn -0.3096 -0.9065 -0.2870 +vn 0.1649 0.2888 -0.9431 +vn 0.3055 0.8996 0.3122 +vn 0.4192 0.8802 -0.2223 +vn 0.2315 0.2646 -0.9362 +vn 0.2405 0.4678 0.8504 +vn 0.2262 0.9668 0.1191 +vn 0.4710 0.5553 0.6854 +vn -0.1776 -0.5190 0.8361 +vn -0.1503 -0.2427 0.9584 +vn 0.3080 0.2436 -0.9196 +vn -0.2780 -0.3330 -0.9010 +vn 0.0223 0.5529 -0.8329 +vn -0.0710 0.4335 -0.8983 +vn 0.3213 0.9325 0.1650 +vn 0.0219 0.5137 -0.8577 +vn -0.2460 -0.3500 -0.9038 +vn 0.4149 0.8943 0.1673 +vn 0.1976 0.8891 -0.4128 +vn 0.2935 0.9118 0.2870 +vn 0.2593 0.3466 0.9015 +vn 0.3653 0.2965 0.8824 +vn 0.0279 -0.5425 0.8396 +vn -0.4259 -0.8463 -0.3200 +vn -0.5444 -0.7857 -0.2936 +vn 0.2112 -0.4708 0.8566 +vn 0.1597 -0.4270 0.8900 +vn 0.6535 0.7044 0.2770 +vn -0.6478 -0.7191 -0.2514 +vn -0.2917 -0.9526 -0.0858 +vn -0.3584 -0.7995 -0.4819 +vn -0.3574 0.0574 -0.9322 +vn 0.5787 -0.7143 -0.3935 +vn -0.1370 -0.6011 0.7873 +vn -0.0056 0.3306 -0.9437 +vn -0.7191 -0.6192 -0.3154 +vn -0.0489 -0.5882 0.8072 +vn 0.6641 0.7262 -0.1772 +vn 0.8174 0.5682 0.0946 +vn 0.5887 0.1395 0.7962 +vn -0.0035 -0.4845 0.8747 +vn 0.2231 0.3485 0.9104 +vn -0.1620 -0.8888 0.4288 +vn 0.5498 0.7719 0.3191 +vn -0.1678 0.5105 -0.8433 +vn -0.2108 0.5521 -0.8066 +vn -0.7349 -0.6480 -0.1998 +vn -0.3612 0.5007 -0.7866 +vn -0.8029 -0.5783 -0.1442 +vn 0.7381 0.6359 0.2253 +vn 0.5594 0.7796 -0.2817 +vn 0.7716 0.0612 0.6331 +vn 0.5790 -0.0757 -0.8118 +vn 0.8507 0.0361 0.5244 +vn 0.1301 -0.9365 -0.3255 +vn 0.0791 -0.7177 0.6918 +vn 0.2486 -0.5192 0.8177 +vn -0.1241 0.4698 -0.8740 +vn 0.0031 -0.5061 -0.8625 +vn 0.1137 -0.5532 -0.8253 +vn 0.3771 0.4194 -0.8257 +vn 0.4036 0.3959 -0.8248 +vn 0.4224 0.3684 -0.8282 +vn 0.1464 -0.5830 -0.7992 +vn 0.2522 0.9635 0.0900 +vn 0.3837 0.8222 -0.4203 +vn 0.1733 0.9698 0.1712 +vn 0.3467 0.9271 0.1423 +vn -0.3541 -0.3695 0.8591 +vn -0.3487 -0.9318 -0.1012 +vn -0.4210 -0.8488 -0.3199 +vn -0.1549 -0.2837 0.9463 +vn -0.2965 -0.4002 0.8671 +vn 0.5320 0.7644 0.3642 +vn -0.5374 -0.7741 -0.3345 +vn -0.2581 -0.9661 0.0035 +vn -0.1602 -0.9075 -0.3883 +vn -0.1307 0.5641 0.8152 +vn -0.0023 0.5151 0.8571 +vn -0.4272 -0.4334 0.7935 +vn -0.0439 0.5108 -0.8585 +vn -0.3514 -0.8269 0.4390 +vn -0.4079 -0.3164 0.8564 +vn -0.1732 0.5848 0.7924 +vn 0.1436 0.4361 0.8884 +vn 0.1359 0.3755 -0.9168 +vn 0.6275 0.6902 0.3602 +vn 0.1940 0.3276 -0.9246 +vn -0.6355 -0.6972 -0.3316 +vn -0.1028 -0.3381 0.9355 +vn 0.4899 0.2112 0.8458 +vn -0.2358 -0.5820 0.7783 +vn 0.4576 0.8719 0.1745 +vn 0.2586 0.2839 -0.9233 +vn -0.3373 -0.5401 -0.7710 +vn -0.2911 -0.5230 -0.8010 +vn -0.2152 0.3646 -0.9059 +vn -0.1657 -0.5139 -0.8417 +vn -0.1409 0.4553 -0.8791 +vn -0.2230 -0.8728 -0.4340 +vn -0.1412 -0.9821 0.1249 +vn -0.2022 0.3330 -0.9210 +vn -0.0211 0.8485 -0.5287 +vn -0.0064 0.8438 -0.5365 +vn 0.0340 0.9983 0.0465 +vn 0.0806 -0.4100 0.9085 +vn 0.0663 -0.9691 -0.2376 +vn 0.1438 -0.4010 0.9047 +vn -0.0450 -0.9990 0.0016 +vn 0.0006 0.4969 0.8678 +vn -0.2161 0.9332 0.2872 +vn -0.0023 -0.2502 0.9682 +vn 0.2092 -0.9437 -0.2562 +vn 0.1741 0.9799 0.0978 +vn 0.2107 0.9761 0.0520 +vn 0.1911 -0.4754 0.8588 +vn -0.0143 -0.8371 0.5469 +vn 0.2123 -0.3723 0.9035 +vn 0.1679 0.5257 0.8339 +vn -0.2234 0.5108 -0.8301 +vn -0.0609 0.1881 -0.9803 +vn 0.4147 -0.8600 -0.2971 +vn -0.6380 -0.5984 -0.4845 +vn -0.8559 -0.2000 0.4769 +vn 0.3105 0.5283 0.7902 +vn 0.3626 0.5199 0.7735 +vn -0.3341 0.8992 0.2824 +vn 0.0513 0.3305 -0.9424 +vn -0.3345 0.8986 -0.2837 +vn 0.1527 0.2390 -0.9589 +vn 0.3337 -0.9073 -0.2560 +vn -0.0103 0.3071 -0.9516 +vn -0.0632 -0.2832 0.9570 +vn -0.4047 0.4406 0.8013 +vn -0.5605 0.8278 0.0251 +vn -0.5196 0.4943 0.6969 +vn -0.2127 -0.3999 0.8915 +vn -0.0196 -0.5568 0.8304 +vn -0.8034 -0.4728 -0.3619 +vn 0.4434 -0.8629 -0.2423 +vn -0.0927 0.9923 0.0820 +vn -0.0796 0.2860 -0.9549 +vn -0.4709 -0.5778 -0.6666 +vn -0.5116 -0.5952 -0.6196 +vn -0.0887 -0.9793 0.1819 +vn -0.4198 -0.6875 -0.5925 +vn -0.0129 -0.9991 0.0390 +vn -0.3460 -0.5724 -0.7434 +vn -0.4411 0.2903 -0.8491 +vn -0.4534 0.3312 -0.8274 +vn -0.3641 0.4206 -0.8310 +vn -0.1610 0.8441 -0.5113 +vn 0.3425 0.5808 0.7385 +vn 0.1752 0.5577 0.8113 +vn 0.3735 -0.3576 0.8559 +vn 0.0222 0.5172 0.8556 +vn 0.3059 -0.3671 0.8784 +vn -0.1060 0.9916 0.0732 +vn 0.0188 0.9997 0.0117 +vn 0.2483 -0.3821 0.8901 +vn 0.0494 -0.9766 -0.2091 +vn 0.1889 -0.9468 -0.2604 +vn 0.4849 0.5793 0.6551 +vn 0.4478 -0.3357 0.8287 +vn 0.4283 -0.4289 0.7953 +vn 0.5366 0.5806 0.6122 +vn 0.1267 -0.8365 0.5332 +vn 0.1767 0.9838 0.0290 +vn 0.2127 0.9770 -0.0112 +vn -0.1494 0.8393 -0.5227 +vn 0.3096 -0.9065 -0.2870 +vn -0.1649 0.2887 -0.9431 +vn -0.3055 0.8995 0.3122 +vn -0.4193 0.8802 -0.2223 +vn -0.2315 0.2646 -0.9362 +vn -0.2405 0.4678 0.8505 +vn -0.2262 0.9668 0.1191 +vn -0.4710 0.5553 0.6854 +vn 0.1776 -0.5189 0.8361 +vn 0.1502 -0.2427 0.9584 +vn -0.3080 0.2436 -0.9196 +vn -0.0224 0.5529 -0.8329 +vn 0.2781 -0.3330 -0.9010 +vn 0.0710 0.4335 -0.8983 +vn -0.3213 0.9325 0.1650 +vn -0.0219 0.5137 -0.8577 +vn 0.2460 -0.3501 -0.9038 +vn -0.4149 0.8943 0.1672 +vn -0.1976 0.8891 -0.4129 +vn -0.2935 0.9118 0.2871 +vn -0.2592 0.3466 0.9015 +vn -0.3653 0.2965 0.8824 +vn 0.4259 -0.8463 -0.3200 +vn -0.0279 -0.5424 0.8396 +vn 0.5444 -0.7857 -0.2936 +vn -0.1598 -0.4270 0.8900 +vn -0.2112 -0.4708 0.8566 +vn -0.6534 0.7045 0.2770 +vn 0.6478 -0.7191 -0.2514 +vn 0.2917 -0.9526 -0.0858 +vn 0.3584 -0.7996 -0.4819 +vn -0.5781 -0.7138 -0.3953 +vn 0.3573 0.0574 -0.9322 +vn 0.1370 -0.6010 0.7874 +vn 0.0056 0.3307 -0.9437 +vn 0.7191 -0.6191 -0.3154 +vn 0.0489 -0.5882 0.8072 +vn -0.6642 0.7262 -0.1772 +vn -0.5887 0.1394 0.7962 +vn -0.8173 0.5683 0.0946 +vn 0.0035 -0.4846 0.8747 +vn -0.2230 0.3484 0.9104 +vn 0.1620 -0.8887 0.4288 +vn -0.5499 0.7719 0.3191 +vn 0.2108 0.5521 -0.8067 +vn 0.1679 0.5105 -0.8433 +vn 0.7349 -0.6481 -0.1998 +vn 0.3612 0.5007 -0.7866 +vn 0.8030 -0.5783 -0.1442 +vn -0.7382 0.6359 0.2253 +vn -0.5594 0.7795 -0.2817 +vn -0.7716 0.0612 0.6331 +vn -0.5785 -0.0792 -0.8118 +vn -0.8507 0.0361 0.5244 +vn -0.1292 -0.9370 -0.3244 +vn -0.0791 -0.7177 0.6919 +vn -0.2486 -0.5192 0.8177 +vn 0.1241 0.4699 -0.8740 +vn -0.1137 -0.5531 -0.8253 +vn -0.0031 -0.5060 -0.8625 +vn -0.3771 0.4194 -0.8257 +vn -0.4037 0.3959 -0.8248 +vn -0.4224 0.3683 -0.8282 +vn -0.1464 -0.5830 -0.7991 +vn -0.2522 0.9635 0.0900 +vn -0.3837 0.8222 -0.4203 +vn -0.1733 0.9698 0.1712 +vn -0.3467 0.9271 0.1422 +vn 0.3487 -0.9318 -0.1012 +vn 0.3540 -0.3695 0.8591 +vn 0.4210 -0.8488 -0.3199 +vn 0.2965 -0.4002 0.8671 +vn 0.1548 -0.2837 0.9463 +vn -0.5320 0.7644 0.3642 +vn 0.5374 -0.7742 -0.3345 +vn 0.2581 -0.9661 0.0036 +vn 0.1600 -0.9073 -0.3889 +vn 0.1307 0.5642 0.8152 +vn 0.0023 0.5150 0.8571 +vn 0.4271 -0.4333 0.7936 +vn 0.0439 0.5107 -0.8586 +vn 0.3514 -0.8268 0.4391 +vn 0.4079 -0.3164 0.8564 +vn 0.1732 0.5848 0.7924 +vn -0.1436 0.4361 0.8883 +vn -0.1359 0.3755 -0.9168 +vn -0.6275 0.6902 0.3603 +vn -0.1940 0.3276 -0.9246 +vn 0.6355 -0.6972 -0.3316 +vn 0.1028 -0.3381 0.9355 +vn -0.4899 0.2112 0.8458 +vn 0.2358 -0.5820 0.7783 +vn -0.4576 0.8719 0.1745 +vn -0.2586 0.2839 -0.9233 +f 2148/2148/2148 2149/2149/2149 2150/2150/2150 +f 2151/2151/2151 2148/2148/2148 2152/2152/2152 +f 2148/2148/2148 2153/2153/2153 2154/2154/2154 +f 2155/2155/2155 2148/2148/2148 2150/2150/2150 +f 2148/2148/2148 2155/2155/2155 2152/2152/2152 +f 2156/2156/2156 2157/2157/2157 2150/2150/2150 +f 2157/2157/2157 2155/2155/2155 2150/2150/2150 +f 2155/2155/2155 2157/2157/2157 2152/2152/2152 +f 2157/2157/2157 2158/2158/2158 2152/2152/2152 +f 2159/2159/2159 2160/2160/2160 2161/2161/2161 +f 2161/2161/2161 2162/2162/2162 2159/2159/2159 +f 2163/2163/2163 2164/2164/2164 2160/2160/2160 +f 2160/2160/2160 2165/2165/2165 2163/2163/2163 +f 2165/2165/2165 2160/2160/2160 2159/2159/2159 +f 2148/2148/2148 2151/2151/2151 2162/2162/2162 +f 2149/2149/2149 2148/2148/2148 2154/2154/2154 +f 2159/2159/2159 2166/2166/2166 2165/2165/2165 +f 2153/2153/2153 2148/2148/2148 2162/2162/2162 +f 2167/2167/2167 2157/2157/2157 2168/2168/2168 +f 2153/2153/2153 2169/2169/2169 2154/2154/2154 +f 2169/2169/2169 2170/2170/2170 2154/2154/2154 +f 2171/2171/2171 2161/2161/2161 2172/2172/2172 +f 2171/2171/2171 2169/2169/2169 2161/2161/2161 +f 2161/2161/2161 2169/2169/2169 2162/2162/2162 +f 2173/2173/2173 2174/2174/2174 2175/2175/2175 +f 2174/2174/2174 2176/2176/2176 2175/2175/2175 +f 2169/2169/2169 2153/2153/2153 2162/2162/2162 +f 2174/2174/2174 2177/2177/2177 2176/2176/2176 +f 2167/2167/2167 2178/2178/2178 2172/2172/2172 +f 2172/2172/2172 2158/2158/2158 2167/2167/2167 +f 2157/2157/2157 2156/2156/2156 2168/2168/2168 +f 2158/2158/2158 2157/2157/2157 2167/2167/2167 +f 2179/2179/2179 2178/2178/2178 2168/2168/2168 +f 2178/2178/2178 2179/2179/2179 2169/2169/2169 +f 2172/2172/2172 2178/2178/2178 2171/2171/2171 +f 2178/2178/2178 2167/2167/2167 2168/2168/2168 +f 2171/2171/2171 2178/2178/2178 2169/2169/2169 +f 2164/2164/2164 2172/2172/2172 2161/2161/2161 +f 2180/2180/2180 2181/2181/2181 2182/2182/2182 +f 2182/2182/2182 2183/2183/2183 2180/2180/2180 +f 2180/2180/2180 2184/2184/2184 2185/2185/2185 +f 2183/2183/2183 2184/2184/2184 2180/2180/2180 +f 2163/2163/2163 2181/2181/2181 2185/2185/2185 +f 2186/2186/2186 2181/2181/2181 2163/2163/2163 +f 2163/2163/2163 2165/2165/2165 2186/2186/2186 +f 2181/2181/2181 2180/2180/2180 2185/2185/2185 +f 2181/2181/2181 2187/2187/2187 2182/2182/2182 +f 2188/2188/2188 2189/2189/2189 2187/2187/2187 +f 2190/2190/2190 2188/2188/2188 2191/2191/2191 +f 2189/2189/2189 2188/2188/2188 2190/2190/2190 +f 2190/2190/2190 2192/2192/2192 2189/2189/2189 +f 2188/2188/2188 2187/2187/2187 2191/2191/2191 +f 2183/2183/2183 2193/2193/2193 2184/2184/2184 +f 2185/2185/2185 2184/2184/2184 2166/2166/2166 +f 2192/2192/2192 2190/2190/2190 2193/2193/2193 +f 2190/2190/2190 2191/2191/2191 2193/2193/2193 +f 2187/2187/2187 2181/2181/2181 2186/2186/2186 +f 2194/2194/2194 2163/2163/2163 2185/2185/2185 +f 2158/2158/2158 2194/2194/2194 2195/2195/2195 +f 2151/2151/2151 2152/2152/2152 2195/2195/2195 +f 2195/2195/2195 2194/2194/2194 2185/2185/2185 +f 2195/2195/2195 2152/2152/2152 2158/2158/2158 +f 2164/2164/2164 2194/2194/2194 2158/2158/2158 +f 2160/2160/2160 2164/2164/2164 2161/2161/2161 +f 2194/2194/2194 2164/2164/2164 2163/2163/2163 +f 2172/2172/2172 2164/2164/2164 2158/2158/2158 +f 2186/2186/2186 2165/2165/2165 2166/2166/2166 +f 2191/2191/2191 2186/2186/2186 2184/2184/2184 +f 2186/2186/2186 2191/2191/2191 2187/2187/2187 +f 2184/2184/2184 2186/2186/2186 2166/2166/2166 +f 2184/2184/2184 2193/2193/2193 2191/2191/2191 +f 2151/2151/2151 2195/2195/2195 2159/2159/2159 +f 2159/2159/2159 2162/2162/2162 2151/2151/2151 +f 2159/2159/2159 2195/2195/2195 2185/2185/2185 +f 2185/2185/2185 2166/2166/2166 2159/2159/2159 +f 2196/2196/2196 2197/2197/2197 2198/2198/2198 +f 2197/2197/2197 2199/2199/2199 2198/2198/2198 +f 2199/2199/2199 2197/2197/2197 2200/2200/2200 +f 2197/2197/2197 2201/2201/2201 2200/2200/2200 +f 2202/2202/2202 2197/2197/2197 2203/2203/2203 +f 2197/2197/2197 2202/2202/2202 2204/2204/2204 +f 2202/2202/2202 2205/2205/2205 2204/2204/2204 +f 2197/2197/2197 2196/2196/2196 2203/2203/2203 +f 2201/2201/2201 2197/2197/2197 2204/2204/2204 +f 2206/2206/2206 2207/2207/2207 2208/2208/2208 +f 2209/2209/2209 2206/2206/2206 2210/2210/2210 +f 2206/2206/2206 2211/2211/2211 2212/2212/2212 +f 2210/2210/2210 2206/2206/2206 2208/2208/2208 +f 2210/2210/2210 2213/2213/2213 2209/2209/2209 +f 2213/2213/2213 2210/2210/2210 2214/2214/2214 +f 2214/2214/2214 2215/2215/2215 2213/2213/2213 +f 2214/2214/2214 2210/2210/2210 2208/2208/2208 +f 2208/2208/2208 2200/2200/2200 2214/2214/2214 +f 2205/2205/2205 2212/2212/2212 2204/2204/2204 +f 2207/2207/2207 2216/2216/2216 2217/2217/2217 +f 2217/2217/2217 2208/2208/2208 2207/2207/2207 +f 2217/2217/2217 2216/2216/2216 2218/2218/2218 +f 2216/2216/2216 2219/2219/2219 2218/2218/2218 +f 2217/2217/2217 2218/2218/2218 2208/2208/2208 +f 2208/2208/2208 2218/2218/2218 2200/2200/2200 +f 2218/2218/2218 2199/2199/2199 2200/2200/2200 +f 2199/2199/2199 2218/2218/2218 2198/2198/2198 +f 2218/2218/2218 2220/2220/2220 2198/2198/2198 +f 2221/2221/2221 2205/2205/2205 2222/2222/2222 +f 2205/2205/2205 2223/2223/2223 2222/2222/2222 +f 2223/2223/2223 2205/2205/2205 2203/2203/2203 +f 2205/2205/2205 2202/2202/2202 2203/2203/2203 +f 2212/2212/2212 2205/2205/2205 2221/2221/2221 +f 2219/2219/2219 2216/2216/2216 2222/2222/2222 +f 2216/2216/2216 2221/2221/2221 2222/2222/2222 +f 2221/2221/2221 2216/2216/2216 2207/2207/2207 +f 2207/2207/2207 2212/2212/2212 2221/2221/2221 +f 2207/2207/2207 2206/2206/2206 2212/2212/2212 +f 2173/2173/2173 2224/2224/2224 2225/2225/2225 +f 2225/2225/2225 2226/2226/2226 2227/2227/2227 +f 2228/2228/2228 2224/2224/2224 2215/2215/2215 +f 2225/2225/2225 2224/2224/2224 2228/2228/2228 +f 2227/2227/2227 2173/2173/2173 2225/2225/2225 +f 2226/2226/2226 2229/2229/2229 2227/2227/2227 +f 2226/2226/2226 2230/2230/2230 2209/2209/2209 +f 2230/2230/2230 2226/2226/2226 2228/2228/2228 +f 2226/2226/2226 2225/2225/2225 2228/2228/2228 +f 2227/2227/2227 2174/2174/2174 2173/2173/2173 +f 2227/2227/2227 2229/2229/2229 2231/2231/2231 +f 2174/2174/2174 2227/2227/2227 2231/2231/2231 +f 2231/2231/2231 2177/2177/2177 2174/2174/2174 +f 2177/2177/2177 2231/2231/2231 2232/2232/2232 +f 2177/2177/2177 2232/2232/2232 2175/2175/2175 +f 2173/2173/2173 2175/2175/2175 2224/2224/2224 +f 2231/2231/2231 2229/2229/2229 2232/2232/2232 +f 2176/2176/2176 2177/2177/2177 2175/2175/2175 +f 2233/2233/2233 2226/2226/2226 2209/2209/2209 +f 2201/2201/2201 2204/2204/2204 2234/2234/2234 +f 2234/2234/2234 2211/2211/2211 2228/2228/2228 +f 2201/2201/2201 2234/2234/2234 2214/2214/2214 +f 2214/2214/2214 2200/2200/2200 2201/2201/2201 +f 2211/2211/2211 2230/2230/2230 2228/2228/2228 +f 2211/2211/2211 2206/2206/2206 2230/2230/2230 +f 2206/2206/2206 2209/2209/2209 2230/2230/2230 +f 2212/2212/2212 2211/2211/2211 2234/2234/2234 +f 2234/2234/2234 2204/2204/2204 2212/2212/2212 +f 2233/2233/2233 2232/2232/2232 2229/2229/2229 +f 2224/2224/2224 2233/2233/2233 2215/2215/2215 +f 2209/2209/2209 2213/2213/2213 2233/2233/2233 +f 2229/2229/2229 2226/2226/2226 2233/2233/2233 +f 2233/2233/2233 2213/2213/2213 2215/2215/2215 +f 2214/2214/2214 2234/2234/2234 2228/2228/2228 +f 2228/2228/2228 2215/2215/2215 2214/2214/2214 +f 2232/2232/2232 2233/2233/2233 2224/2224/2224 +f 2224/2224/2224 2175/2175/2175 2232/2232/2232 +f 2235/2235/2235 2236/2236/2236 2237/2237/2237 +f 2236/2236/2236 2238/2238/2238 2237/2237/2237 +f 2236/2236/2236 2235/2235/2235 2239/2239/2239 +f 2235/2235/2235 2240/2240/2240 2239/2239/2239 +f 2238/2238/2238 2241/2241/2241 2237/2237/2237 +f 2238/2238/2238 2242/2242/2242 2243/2243/2243 +f 2238/2238/2238 2244/2244/2244 2245/2245/2245 +f 2242/2242/2242 2238/2238/2238 2239/2239/2239 +f 2238/2238/2238 2236/2236/2236 2239/2239/2239 +f 2246/2246/2246 2247/2247/2247 2248/2248/2248 +f 2249/2249/2249 2250/2250/2250 2248/2248/2248 +f 2250/2250/2250 2249/2249/2249 2251/2251/2251 +f 2248/2248/2248 2250/2250/2250 2246/2246/2246 +f 2248/2248/2248 2252/2252/2252 2249/2249/2249 +f 2240/2240/2240 2235/2235/2235 2253/2253/2253 +f 2235/2235/2235 2254/2254/2254 2253/2253/2253 +f 2254/2254/2254 2235/2235/2235 2247/2247/2247 +f 2235/2235/2235 2237/2237/2237 2247/2247/2247 +f 2245/2245/2245 2241/2241/2241 2238/2238/2238 +f 2255/2255/2255 2256/2256/2256 2257/2257/2257 +f 2258/2258/2258 2255/2255/2255 2259/2259/2259 +f 2246/2246/2246 2260/2260/2260 2247/2247/2247 +f 2260/2260/2260 2254/2254/2254 2247/2247/2247 +f 2255/2255/2255 2257/2257/2257 2259/2259/2259 +f 2261/2261/2261 2255/2255/2255 2258/2258/2258 +f 2262/2262/2262 2263/2263/2263 2257/2257/2257 +f 2255/2255/2255 2261/2261/2261 2262/2262/2262 +f 2262/2262/2262 2256/2256/2256 2255/2255/2255 +f 2264/2264/2264 2244/2244/2244 2260/2260/2260 +f 2244/2244/2244 2265/2265/2265 2260/2260/2260 +f 2265/2265/2265 2244/2244/2244 2243/2243/2243 +f 2244/2244/2244 2238/2238/2238 2243/2243/2243 +f 2245/2245/2245 2244/2244/2244 2264/2264/2264 +f 2254/2254/2254 2260/2260/2260 2253/2253/2253 +f 2260/2260/2260 2266/2266/2266 2253/2253/2253 +f 2264/2264/2264 2246/2246/2246 2245/2245/2245 +f 2264/2264/2264 2260/2260/2260 2246/2246/2246 +f 2251/2251/2251 2267/2267/2267 2250/2250/2250 +f 2268/2268/2268 2269/2269/2269 2252/2252/2252 +f 2269/2269/2269 2270/2270/2270 2252/2252/2252 +f 2270/2270/2270 2269/2269/2269 2271/2271/2271 +f 2271/2271/2271 2272/2272/2272 2270/2270/2270 +f 2269/2269/2269 2273/2273/2273 2274/2274/2274 +f 2273/2273/2273 2269/2269/2269 2268/2268/2268 +f 2275/2275/2275 2274/2274/2274 2273/2273/2273 +f 2274/2274/2274 2271/2271/2271 2269/2269/2269 +f 2251/2251/2251 2273/2273/2273 2268/2268/2268 +f 2274/2274/2274 2276/2276/2276 2271/2271/2271 +f 2276/2276/2276 2277/2277/2277 2278/2278/2278 +f 2271/2271/2271 2276/2276/2276 2272/2272/2272 +f 2276/2276/2276 2278/2278/2278 2272/2272/2272 +f 2275/2275/2275 2277/2277/2277 2274/2274/2274 +f 2277/2277/2277 2275/2275/2275 2279/2279/2279 +f 2278/2278/2278 2279/2279/2279 2272/2272/2272 +f 2277/2277/2277 2276/2276/2276 2274/2274/2274 +f 2278/2278/2278 2277/2277/2277 2279/2279/2279 +f 2280/2280/2280 2273/2273/2273 2251/2251/2251 +f 2281/2281/2281 2267/2267/2267 2268/2268/2268 +f 2267/2267/2267 2251/2251/2251 2268/2268/2268 +f 2237/2237/2237 2281/2281/2281 2248/2248/2248 +f 2248/2248/2248 2247/2247/2247 2237/2237/2237 +f 2241/2241/2241 2267/2267/2267 2281/2281/2281 +f 2250/2250/2250 2267/2267/2267 2246/2246/2246 +f 2267/2267/2267 2245/2245/2245 2246/2246/2246 +f 2281/2281/2281 2237/2237/2237 2241/2241/2241 +f 2245/2245/2245 2267/2267/2267 2241/2241/2241 +f 2280/2280/2280 2279/2279/2279 2275/2275/2275 +f 2270/2270/2270 2280/2280/2280 2252/2252/2252 +f 2251/2251/2251 2249/2249/2249 2280/2280/2280 +f 2275/2275/2275 2273/2273/2273 2280/2280/2280 +f 2280/2280/2280 2249/2249/2249 2252/2252/2252 +f 2248/2248/2248 2281/2281/2281 2268/2268/2268 +f 2268/2268/2268 2252/2252/2252 2248/2248/2248 +f 2279/2279/2279 2280/2280/2280 2270/2270/2270 +f 2270/2270/2270 2272/2272/2272 2279/2279/2279 +f 2282/2282/2282 2283/2283/2283 2284/2284/2284 +f 2283/2283/2283 2285/2285/2285 2284/2284/2284 +f 2285/2285/2285 2283/2283/2283 2286/2286/2286 +f 2283/2283/2283 2287/2287/2287 2286/2286/2286 +f 2285/2285/2285 2288/2288/2288 2284/2284/2284 +f 2288/2288/2288 2285/2285/2285 2286/2286/2286 +f 2288/2288/2288 2289/2289/2289 2290/2290/2290 +f 2288/2288/2288 2291/2291/2291 2284/2284/2284 +f 2289/2289/2289 2288/2288/2288 2286/2286/2286 +f 2292/2292/2292 2293/2293/2293 2294/2294/2294 +f 2295/2295/2295 2296/2296/2296 2294/2294/2294 +f 2296/2296/2296 2295/2295/2295 2297/2297/2297 +f 2294/2294/2294 2296/2296/2296 2292/2292/2292 +f 2294/2294/2294 2298/2298/2298 2295/2295/2295 +f 2287/2287/2287 2283/2283/2283 2299/2299/2299 +f 2283/2283/2283 2300/2300/2300 2299/2299/2299 +f 2300/2300/2300 2283/2283/2283 2293/2293/2293 +f 2283/2283/2283 2282/2282/2282 2293/2293/2293 +f 2288/2288/2288 2301/2301/2301 2302/2302/2302 +f 2303/2303/2303 2300/2300/2300 2293/2293/2293 +f 2183/2183/2183 2304/2304/2304 2193/2193/2193 +f 2303/2303/2303 2305/2305/2305 2299/2299/2299 +f 2292/2292/2292 2303/2303/2303 2293/2293/2293 +f 2304/2304/2304 2192/2192/2192 2193/2193/2193 +f 2182/2182/2182 2304/2304/2304 2183/2183/2183 +f 2182/2182/2182 2187/2187/2187 2189/2189/2189 +f 2304/2304/2304 2182/2182/2182 2189/2189/2189 +f 2189/2189/2189 2192/2192/2192 2304/2304/2304 +f 2301/2301/2301 2288/2288/2288 2290/2290/2290 +f 2306/2306/2306 2301/2301/2301 2303/2303/2303 +f 2302/2302/2302 2291/2291/2291 2288/2288/2288 +f 2307/2307/2307 2301/2301/2301 2290/2290/2290 +f 2301/2301/2301 2307/2307/2307 2303/2303/2303 +f 2306/2306/2306 2303/2303/2303 2292/2292/2292 +f 2300/2300/2300 2303/2303/2303 2299/2299/2299 +f 2302/2302/2302 2301/2301/2301 2306/2306/2306 +f 2306/2306/2306 2292/2292/2292 2302/2302/2302 +f 2297/2297/2297 2308/2308/2308 2296/2296/2296 +f 2261/2261/2261 2258/2258/2258 2309/2309/2309 +f 2297/2297/2297 2310/2310/2310 2311/2311/2311 +f 2258/2258/2258 2312/2312/2312 2309/2309/2309 +f 2309/2309/2309 2310/2310/2310 2261/2261/2261 +f 2310/2310/2310 2309/2309/2309 2311/2311/2311 +f 2297/2297/2297 2295/2295/2295 2313/2313/2313 +f 2314/2314/2314 2310/2310/2310 2313/2313/2313 +f 2314/2314/2314 2261/2261/2261 2310/2310/2310 +f 2313/2313/2313 2310/2310/2310 2297/2297/2297 +f 2263/2263/2263 2262/2262/2262 2261/2261/2261 +f 2257/2257/2257 2263/2263/2263 2315/2315/2315 +f 2257/2257/2257 2256/2256/2256 2262/2262/2262 +f 2314/2314/2314 2263/2263/2263 2261/2261/2261 +f 2263/2263/2263 2314/2314/2314 2315/2315/2315 +f 2311/2311/2311 2312/2312/2312 2298/2298/2298 +f 2309/2309/2309 2312/2312/2312 2311/2311/2311 +f 2257/2257/2257 2315/2315/2315 2259/2259/2259 +f 2258/2258/2258 2259/2259/2259 2312/2312/2312 +f 2313/2313/2313 2315/2315/2315 2314/2314/2314 +f 2291/2291/2291 2316/2316/2316 2317/2317/2317 +f 2317/2317/2317 2284/2284/2284 2291/2291/2291 +f 2317/2317/2317 2316/2316/2316 2311/2311/2311 +f 2316/2316/2316 2297/2297/2297 2311/2311/2311 +f 2316/2316/2316 2308/2308/2308 2297/2297/2297 +f 2296/2296/2296 2308/2308/2308 2292/2292/2292 +f 2308/2308/2308 2302/2302/2302 2292/2292/2292 +f 2302/2302/2302 2308/2308/2308 2291/2291/2291 +f 2308/2308/2308 2316/2316/2316 2291/2291/2291 +f 2315/2315/2315 2313/2313/2313 2312/2312/2312 +f 2312/2312/2312 2259/2259/2259 2315/2315/2315 +f 2312/2312/2312 2313/2313/2313 2298/2298/2298 +f 2313/2313/2313 2295/2295/2295 2298/2298/2298 +f 2294/2294/2294 2317/2317/2317 2311/2311/2311 +f 2294/2294/2294 2293/2293/2293 2282/2282/2282 +f 2282/2282/2282 2284/2284/2284 2317/2317/2317 +f 2311/2311/2311 2298/2298/2298 2294/2294/2294 +f 2282/2282/2282 2317/2317/2317 2294/2294/2294 +f 2318/2318/2318 2319/2319/2319 2320/2320/2320 +f 2319/2319/2319 2321/2321/2321 2322/2322/2322 +f 2323/2323/2323 2319/2319/2319 2324/2324/2324 +f 2319/2319/2319 2325/2325/2325 2320/2320/2320 +f 2325/2325/2325 2319/2319/2319 2322/2322/2322 +f 2326/2326/2326 2327/2327/2327 2320/2320/2320 +f 2325/2325/2325 2326/2326/2326 2320/2320/2320 +f 2326/2326/2326 2325/2325/2325 2322/2322/2322 +f 2328/2328/2328 2326/2326/2326 2322/2322/2322 +f 2329/2329/2329 2330/2330/2330 2331/2331/2331 +f 2332/2332/2332 2331/2331/2331 2330/2330/2330 +f 2333/2333/2333 2334/2334/2334 2329/2329/2329 +f 2335/2335/2335 2329/2329/2329 2334/2334/2334 +f 2329/2329/2329 2335/2335/2335 2330/2330/2330 +f 2321/2321/2321 2319/2319/2319 2332/2332/2332 +f 2319/2319/2319 2318/2318/2318 2324/2324/2324 +f 2336/2336/2336 2330/2330/2330 2335/2335/2335 +f 2319/2319/2319 2323/2323/2323 2332/2332/2332 +f 2326/2326/2326 2337/2337/2337 2338/2338/2338 +f 2339/2339/2339 2323/2323/2323 2324/2324/2324 +f 2340/2340/2340 2339/2339/2339 2324/2324/2324 +f 2331/2331/2331 2341/2341/2341 2342/2342/2342 +f 2339/2339/2339 2341/2341/2341 2331/2331/2331 +f 2339/2339/2339 2331/2331/2331 2332/2332/2332 +f 2343/2343/2343 2344/2344/2344 2345/2345/2345 +f 2346/2346/2346 2343/2343/2343 2345/2345/2345 +f 2323/2323/2323 2339/2339/2339 2332/2332/2332 +f 2347/2347/2347 2343/2343/2343 2346/2346/2346 +f 2348/2348/2348 2337/2337/2337 2342/2342/2342 +f 2328/2328/2328 2342/2342/2342 2337/2337/2337 +f 2327/2327/2327 2326/2326/2326 2338/2338/2338 +f 2326/2326/2326 2328/2328/2328 2337/2337/2337 +f 2348/2348/2348 2349/2349/2349 2338/2338/2338 +f 2349/2349/2349 2348/2348/2348 2339/2339/2339 +f 2348/2348/2348 2342/2342/2342 2341/2341/2341 +f 2337/2337/2337 2348/2348/2348 2338/2338/2338 +f 2348/2348/2348 2341/2341/2341 2339/2339/2339 +f 2342/2342/2342 2333/2333/2333 2331/2331/2331 +f 2350/2350/2350 2351/2351/2351 2352/2352/2352 +f 2353/2353/2353 2352/2352/2352 2351/2351/2351 +f 2354/2354/2354 2351/2351/2351 2355/2355/2355 +f 2354/2354/2354 2353/2353/2353 2351/2351/2351 +f 2350/2350/2350 2334/2334/2334 2355/2355/2355 +f 2350/2350/2350 2356/2356/2356 2334/2334/2334 +f 2335/2335/2335 2334/2334/2334 2356/2356/2356 +f 2351/2351/2351 2350/2350/2350 2355/2355/2355 +f 2357/2357/2357 2350/2350/2350 2352/2352/2352 +f 2358/2358/2358 2359/2359/2359 2357/2357/2357 +f 2359/2359/2359 2360/2360/2360 2361/2361/2361 +f 2359/2359/2359 2358/2358/2358 2360/2360/2360 +f 2362/2362/2362 2360/2360/2360 2358/2358/2358 +f 2357/2357/2357 2359/2359/2359 2361/2361/2361 +f 2363/2363/2363 2353/2353/2353 2354/2354/2354 +f 2354/2354/2354 2355/2355/2355 2336/2336/2336 +f 2360/2360/2360 2362/2362/2362 2363/2363/2363 +f 2361/2361/2361 2360/2360/2360 2363/2363/2363 +f 2350/2350/2350 2357/2357/2357 2356/2356/2356 +f 2334/2334/2334 2364/2364/2364 2355/2355/2355 +f 2364/2364/2364 2328/2328/2328 2365/2365/2365 +f 2322/2322/2322 2321/2321/2321 2365/2365/2365 +f 2364/2364/2364 2365/2365/2365 2355/2355/2355 +f 2322/2322/2322 2365/2365/2365 2328/2328/2328 +f 2364/2364/2364 2333/2333/2333 2328/2328/2328 +f 2333/2333/2333 2329/2329/2329 2331/2331/2331 +f 2333/2333/2333 2364/2364/2364 2334/2334/2334 +f 2333/2333/2333 2342/2342/2342 2328/2328/2328 +f 2335/2335/2335 2356/2356/2356 2336/2336/2336 +f 2356/2356/2356 2361/2361/2361 2354/2354/2354 +f 2361/2361/2361 2356/2356/2356 2357/2357/2357 +f 2356/2356/2356 2354/2354/2354 2336/2336/2336 +f 2363/2363/2363 2354/2354/2354 2361/2361/2361 +f 2365/2365/2365 2321/2321/2321 2330/2330/2330 +f 2332/2332/2332 2330/2330/2330 2321/2321/2321 +f 2365/2365/2365 2330/2330/2330 2355/2355/2355 +f 2336/2336/2336 2355/2355/2355 2330/2330/2330 +f 2366/2366/2366 2367/2367/2367 2368/2368/2368 +f 2369/2369/2369 2366/2366/2366 2368/2368/2368 +f 2366/2366/2366 2369/2369/2369 2370/2370/2370 +f 2371/2371/2371 2366/2366/2366 2370/2370/2370 +f 2366/2366/2366 2372/2372/2372 2373/2373/2373 +f 2372/2372/2372 2366/2366/2366 2374/2374/2374 +f 2375/2375/2375 2372/2372/2372 2374/2374/2374 +f 2367/2367/2367 2366/2366/2366 2373/2373/2373 +f 2366/2366/2366 2371/2371/2371 2374/2374/2374 +f 2376/2376/2376 2377/2377/2377 2378/2378/2378 +f 2377/2377/2377 2379/2379/2379 2380/2380/2380 +f 2381/2381/2381 2377/2377/2377 2382/2382/2382 +f 2377/2377/2377 2380/2380/2380 2378/2378/2378 +f 2383/2383/2383 2380/2380/2380 2379/2379/2379 +f 2380/2380/2380 2383/2383/2383 2384/2384/2384 +f 2385/2385/2385 2384/2384/2384 2383/2383/2383 +f 2380/2380/2380 2384/2384/2384 2378/2378/2378 +f 2370/2370/2370 2378/2378/2378 2384/2384/2384 +f 2382/2382/2382 2375/2375/2375 2374/2374/2374 +f 2386/2386/2386 2376/2376/2376 2387/2387/2387 +f 2378/2378/2378 2387/2387/2387 2376/2376/2376 +f 2386/2386/2386 2387/2387/2387 2388/2388/2388 +f 2389/2389/2389 2386/2386/2386 2388/2388/2388 +f 2388/2388/2388 2387/2387/2387 2378/2378/2378 +f 2388/2388/2388 2378/2378/2378 2370/2370/2370 +f 2369/2369/2369 2388/2388/2388 2370/2370/2370 +f 2388/2388/2388 2369/2369/2369 2368/2368/2368 +f 2390/2390/2390 2388/2388/2388 2368/2368/2368 +f 2375/2375/2375 2391/2391/2391 2392/2392/2392 +f 2393/2393/2393 2375/2375/2375 2392/2392/2392 +f 2375/2375/2375 2393/2393/2393 2373/2373/2373 +f 2372/2372/2372 2375/2375/2375 2373/2373/2373 +f 2375/2375/2375 2382/2382/2382 2391/2391/2391 +f 2386/2386/2386 2389/2389/2389 2392/2392/2392 +f 2391/2391/2391 2386/2386/2386 2392/2392/2392 +f 2386/2386/2386 2391/2391/2391 2376/2376/2376 +f 2382/2382/2382 2376/2376/2376 2391/2391/2391 +f 2377/2377/2377 2376/2376/2376 2382/2382/2382 +f 2394/2394/2394 2344/2344/2344 2395/2395/2395 +f 2396/2396/2396 2395/2395/2395 2397/2397/2397 +f 2394/2394/2394 2398/2398/2398 2385/2385/2385 +f 2394/2394/2394 2395/2395/2395 2398/2398/2398 +f 2344/2344/2344 2397/2397/2397 2395/2395/2395 +f 2399/2399/2399 2396/2396/2396 2397/2397/2397 +f 2400/2400/2400 2396/2396/2396 2379/2379/2379 +f 2396/2396/2396 2400/2400/2400 2398/2398/2398 +f 2395/2395/2395 2396/2396/2396 2398/2398/2398 +f 2343/2343/2343 2397/2397/2397 2344/2344/2344 +f 2399/2399/2399 2397/2397/2397 2401/2401/2401 +f 2397/2397/2397 2343/2343/2343 2401/2401/2401 +f 2347/2347/2347 2401/2401/2401 2343/2343/2343 +f 2401/2401/2401 2347/2347/2347 2402/2402/2402 +f 2402/2402/2402 2347/2347/2347 2345/2345/2345 +f 2345/2345/2345 2344/2344/2344 2394/2394/2394 +f 2399/2399/2399 2401/2401/2401 2402/2402/2402 +f 2347/2347/2347 2346/2346/2346 2345/2345/2345 +f 2396/2396/2396 2403/2403/2403 2379/2379/2379 +f 2374/2374/2374 2371/2371/2371 2404/2404/2404 +f 2381/2381/2381 2404/2404/2404 2398/2398/2398 +f 2404/2404/2404 2371/2371/2371 2384/2384/2384 +f 2370/2370/2370 2384/2384/2384 2371/2371/2371 +f 2400/2400/2400 2381/2381/2381 2398/2398/2398 +f 2377/2377/2377 2381/2381/2381 2400/2400/2400 +f 2379/2379/2379 2377/2377/2377 2400/2400/2400 +f 2381/2381/2381 2382/2382/2382 2404/2404/2404 +f 2374/2374/2374 2404/2404/2404 2382/2382/2382 +f 2402/2402/2402 2403/2403/2403 2399/2399/2399 +f 2403/2403/2403 2394/2394/2394 2385/2385/2385 +f 2383/2383/2383 2379/2379/2379 2403/2403/2403 +f 2396/2396/2396 2399/2399/2399 2403/2403/2403 +f 2383/2383/2383 2403/2403/2403 2385/2385/2385 +f 2404/2404/2404 2384/2384/2384 2398/2398/2398 +f 2385/2385/2385 2398/2398/2398 2384/2384/2384 +f 2403/2403/2403 2402/2402/2402 2394/2394/2394 +f 2345/2345/2345 2394/2394/2394 2402/2402/2402 +f 2405/2405/2405 2406/2406/2406 2407/2407/2407 +f 2408/2408/2408 2405/2405/2405 2407/2407/2407 +f 2406/2406/2406 2405/2405/2405 2409/2409/2409 +f 2410/2410/2410 2406/2406/2406 2409/2409/2409 +f 2411/2411/2411 2408/2408/2408 2407/2407/2407 +f 2412/2412/2412 2408/2408/2408 2413/2413/2413 +f 2414/2414/2414 2408/2408/2408 2415/2415/2415 +f 2408/2408/2408 2412/2412/2412 2409/2409/2409 +f 2405/2405/2405 2408/2408/2408 2409/2409/2409 +f 2416/2416/2416 2417/2417/2417 2418/2418/2418 +f 2419/2419/2419 2420/2420/2420 2418/2418/2418 +f 2420/2420/2420 2419/2419/2419 2421/2421/2421 +f 2419/2419/2419 2418/2418/2418 2417/2417/2417 +f 2422/2422/2422 2418/2418/2418 2420/2420/2420 +f 2406/2406/2406 2410/2410/2410 2423/2423/2423 +f 2424/2424/2424 2406/2406/2406 2423/2423/2423 +f 2406/2406/2406 2424/2424/2424 2416/2416/2416 +f 2407/2407/2407 2406/2406/2406 2416/2416/2416 +f 2411/2411/2411 2415/2415/2415 2408/2408/2408 +f 2425/2425/2425 2426/2426/2426 2427/2427/2427 +f 2426/2426/2426 2428/2428/2428 2429/2429/2429 +f 2430/2430/2430 2417/2417/2417 2416/2416/2416 +f 2424/2424/2424 2430/2430/2430 2416/2416/2416 +f 2427/2427/2427 2426/2426/2426 2429/2429/2429 +f 2426/2426/2426 2431/2431/2431 2428/2428/2428 +f 2432/2432/2432 2433/2433/2433 2427/2427/2427 +f 2431/2431/2431 2426/2426/2426 2433/2433/2433 +f 2425/2425/2425 2433/2433/2433 2426/2426/2426 +f 2414/2414/2414 2434/2434/2434 2430/2430/2430 +f 2435/2435/2435 2414/2414/2414 2430/2430/2430 +f 2414/2414/2414 2435/2435/2435 2413/2413/2413 +f 2408/2408/2408 2414/2414/2414 2413/2413/2413 +f 2414/2414/2414 2415/2415/2415 2434/2434/2434 +f 2430/2430/2430 2424/2424/2424 2423/2423/2423 +f 2436/2436/2436 2430/2430/2430 2423/2423/2423 +f 2417/2417/2417 2434/2434/2434 2415/2415/2415 +f 2430/2430/2430 2434/2434/2434 2417/2417/2417 +f 2437/2437/2437 2421/2421/2421 2419/2419/2419 +f 2438/2438/2438 2439/2439/2439 2422/2422/2422 +f 2440/2440/2440 2438/2438/2438 2422/2422/2422 +f 2438/2438/2438 2440/2440/2440 2441/2441/2441 +f 2442/2442/2442 2441/2441/2441 2440/2440/2440 +f 2443/2443/2443 2438/2438/2438 2444/2444/2444 +f 2438/2438/2438 2443/2443/2443 2439/2439/2439 +f 2444/2444/2444 2445/2445/2445 2443/2443/2443 +f 2441/2441/2441 2444/2444/2444 2438/2438/2438 +f 2443/2443/2443 2421/2421/2421 2439/2439/2439 +f 2446/2446/2446 2444/2444/2444 2441/2441/2441 +f 2447/2447/2447 2446/2446/2446 2448/2448/2448 +f 2446/2446/2446 2441/2441/2441 2442/2442/2442 +f 2448/2448/2448 2446/2446/2446 2442/2442/2442 +f 2447/2447/2447 2445/2445/2445 2444/2444/2444 +f 2445/2445/2445 2447/2447/2447 2449/2449/2449 +f 2449/2449/2449 2448/2448/2448 2442/2442/2442 +f 2446/2446/2446 2447/2447/2447 2444/2444/2444 +f 2447/2447/2447 2448/2448/2448 2449/2449/2449 +f 2443/2443/2443 2450/2450/2450 2421/2421/2421 +f 2437/2437/2437 2451/2451/2451 2439/2439/2439 +f 2421/2421/2421 2437/2437/2437 2439/2439/2439 +f 2451/2451/2451 2407/2407/2407 2418/2418/2418 +f 2416/2416/2416 2418/2418/2418 2407/2407/2407 +f 2437/2437/2437 2411/2411/2411 2451/2451/2451 +f 2437/2437/2437 2419/2419/2419 2417/2417/2417 +f 2415/2415/2415 2437/2437/2437 2417/2417/2417 +f 2407/2407/2407 2451/2451/2451 2411/2411/2411 +f 2437/2437/2437 2415/2415/2415 2411/2411/2411 +f 2449/2449/2449 2450/2450/2450 2445/2445/2445 +f 2450/2450/2450 2440/2440/2440 2422/2422/2422 +f 2420/2420/2420 2421/2421/2421 2450/2450/2450 +f 2443/2443/2443 2445/2445/2445 2450/2450/2450 +f 2420/2420/2420 2450/2450/2450 2422/2422/2422 +f 2451/2451/2451 2418/2418/2418 2439/2439/2439 +f 2422/2422/2422 2439/2439/2439 2418/2418/2418 +f 2450/2450/2450 2449/2449/2449 2440/2440/2440 +f 2442/2442/2442 2440/2440/2440 2449/2449/2449 +f 2452/2452/2452 2453/2453/2453 2454/2454/2454 +f 2455/2455/2455 2452/2452/2452 2454/2454/2454 +f 2452/2452/2452 2455/2455/2455 2456/2456/2456 +f 2457/2457/2457 2452/2452/2452 2456/2456/2456 +f 2458/2458/2458 2455/2455/2455 2454/2454/2454 +f 2455/2455/2455 2458/2458/2458 2456/2456/2456 +f 2459/2459/2459 2458/2458/2458 2460/2460/2460 +f 2461/2461/2461 2458/2458/2458 2454/2454/2454 +f 2458/2458/2458 2459/2459/2459 2456/2456/2456 +f 2462/2462/2462 2463/2463/2463 2464/2464/2464 +f 2465/2465/2465 2466/2466/2466 2464/2464/2464 +f 2466/2466/2466 2465/2465/2465 2467/2467/2467 +f 2465/2465/2465 2464/2464/2464 2463/2463/2463 +f 2468/2468/2468 2464/2464/2464 2466/2466/2466 +f 2452/2452/2452 2457/2457/2457 2469/2469/2469 +f 2470/2470/2470 2452/2452/2452 2469/2469/2469 +f 2452/2452/2452 2470/2470/2470 2462/2462/2462 +f 2453/2453/2453 2452/2452/2452 2462/2462/2462 +f 2471/2471/2471 2458/2458/2458 2472/2472/2472 +f 2470/2470/2470 2473/2473/2473 2462/2462/2462 +f 2474/2474/2474 2353/2353/2353 2363/2363/2363 +f 2475/2475/2475 2473/2473/2473 2469/2469/2469 +f 2473/2473/2473 2463/2463/2463 2462/2462/2462 +f 2362/2362/2362 2474/2474/2474 2363/2363/2363 +f 2474/2474/2474 2352/2352/2352 2353/2353/2353 +f 2357/2357/2357 2352/2352/2352 2358/2358/2358 +f 2352/2352/2352 2474/2474/2474 2358/2358/2358 +f 2362/2362/2362 2358/2358/2358 2474/2474/2474 +f 2458/2458/2458 2471/2471/2471 2460/2460/2460 +f 2471/2471/2471 2476/2476/2476 2473/2473/2473 +f 2461/2461/2461 2472/2472/2472 2458/2458/2458 +f 2471/2471/2471 2477/2477/2477 2460/2460/2460 +f 2477/2477/2477 2471/2471/2471 2473/2473/2473 +f 2473/2473/2473 2476/2476/2476 2463/2463/2463 +f 2473/2473/2473 2470/2470/2470 2469/2469/2469 +f 2471/2471/2471 2472/2472/2472 2476/2476/2476 +f 2463/2463/2463 2476/2476/2476 2472/2472/2472 +f 2478/2478/2478 2467/2467/2467 2465/2465/2465 +f 2428/2428/2428 2431/2431/2431 2479/2479/2479 +f 2480/2480/2480 2467/2467/2467 2481/2481/2481 +f 2482/2482/2482 2428/2428/2428 2479/2479/2479 +f 2480/2480/2480 2479/2479/2479 2431/2431/2431 +f 2479/2479/2479 2480/2480/2480 2481/2481/2481 +f 2466/2466/2466 2467/2467/2467 2483/2483/2483 +f 2480/2480/2480 2484/2484/2484 2483/2483/2483 +f 2431/2431/2431 2484/2484/2484 2480/2480/2480 +f 2480/2480/2480 2483/2483/2483 2467/2467/2467 +f 2433/2433/2433 2432/2432/2432 2431/2431/2431 +f 2432/2432/2432 2427/2427/2427 2485/2485/2485 +f 2425/2425/2425 2427/2427/2427 2433/2433/2433 +f 2432/2432/2432 2484/2484/2484 2431/2431/2431 +f 2484/2484/2484 2432/2432/2432 2485/2485/2485 +f 2482/2482/2482 2481/2481/2481 2468/2468/2468 +f 2482/2482/2482 2479/2479/2479 2481/2481/2481 +f 2485/2485/2485 2427/2427/2427 2429/2429/2429 +f 2429/2429/2429 2428/2428/2428 2482/2482/2482 +f 2485/2485/2485 2483/2483/2483 2484/2484/2484 +f 2486/2486/2486 2461/2461/2461 2487/2487/2487 +f 2454/2454/2454 2487/2487/2487 2461/2461/2461 +f 2486/2486/2486 2487/2487/2487 2481/2481/2481 +f 2467/2467/2467 2486/2486/2486 2481/2481/2481 +f 2478/2478/2478 2486/2486/2486 2467/2467/2467 +f 2478/2478/2478 2465/2465/2465 2463/2463/2463 +f 2472/2472/2472 2478/2478/2478 2463/2463/2463 +f 2478/2478/2478 2472/2472/2472 2461/2461/2461 +f 2486/2486/2486 2478/2478/2478 2461/2461/2461 +f 2483/2483/2483 2485/2485/2485 2482/2482/2482 +f 2429/2429/2429 2482/2482/2482 2485/2485/2485 +f 2483/2483/2483 2482/2482/2482 2468/2468/2468 +f 2466/2466/2466 2483/2483/2483 2468/2468/2468 +f 2487/2487/2487 2464/2464/2464 2481/2481/2481 +f 2462/2462/2462 2464/2464/2464 2453/2453/2453 +f 2454/2454/2454 2453/2453/2453 2487/2487/2487 +f 2468/2468/2468 2481/2481/2481 2464/2464/2464 +f 2487/2487/2487 2453/2453/2453 2464/2464/2464 +v 0.455831 0.688613 0.635114 +v 0.456179 0.630125 0.619891 +v 0.459729 0.690627 0.624110 +v 0.460063 0.634385 0.610713 +v 0.456548 0.636690 0.600766 +v 0.446787 0.637997 0.596950 +v 0.456403 0.692355 0.612405 +v 0.436461 0.630896 0.619590 +v 0.440540 0.587108 0.604306 +v 0.447247 0.608862 0.615991 +v 0.446133 0.632187 0.624086 +v 0.448511 0.586056 0.607260 +v 0.456521 0.586369 0.604279 +v 0.446284 0.693780 0.608197 +v 0.435253 0.689633 0.634461 +v 0.445382 0.688711 0.638799 +v 0.432051 0.692016 0.623280 +v 0.436901 0.637720 0.600547 +v 0.436003 0.693390 0.611838 +v 0.433055 0.632848 0.609732 +v 0.457621 0.521928 0.568692 +v 0.457679 0.507612 0.564795 +v 0.453726 0.522095 0.567264 +v 0.455213 0.505808 0.563751 +v 0.452377 0.507671 0.564814 +v 0.449777 0.522082 0.568729 +v 0.443255 0.567427 0.581970 +v 0.450000 0.567753 0.579454 +v 0.456574 0.590018 0.588464 +v 0.448394 0.520938 0.572477 +v 0.452197 0.505104 0.566685 +v 0.452366 0.506378 0.569965 +v 0.449750 0.520217 0.576389 +v 0.443176 0.564324 0.595286 +v 0.444371 0.542952 0.580484 +v 0.459033 0.520728 0.572420 +v 0.455205 0.504336 0.569596 +v 0.455672 0.500264 0.564912 +v 0.458222 0.505039 0.566662 +v 0.457676 0.506319 0.569941 +v 0.457611 0.520061 0.576343 +v 0.459239 0.565261 0.588565 +v 0.449922 0.563478 0.597754 +v 0.437597 0.589058 0.596399 +v 0.440637 0.590736 0.588485 +v 0.453700 0.519569 0.577635 +v 0.440687 0.565973 0.588637 +v 0.558742 0.564324 0.595286 +v 0.552168 0.520217 0.576389 +v 0.557547 0.542952 0.580484 +v 0.553524 0.520938 0.572477 +v 0.549541 0.507671 0.564814 +v 0.552141 0.522082 0.568729 +v 0.549552 0.506378 0.569965 +v 0.549721 0.505104 0.566685 +v 0.546705 0.505808 0.563751 +v 0.548192 0.522095 0.567264 +v 0.544239 0.507612 0.564795 +v 0.558663 0.567427 0.581970 +v 0.544242 0.506319 0.569941 +v 0.546713 0.504336 0.569596 +v 0.548218 0.519569 0.577635 +v 0.544307 0.520061 0.576343 +v 0.561231 0.565973 0.588637 +v 0.561281 0.590736 0.588485 +v 0.551918 0.567753 0.579454 +v 0.551996 0.563478 0.597754 +v 0.545397 0.586369 0.604279 +v 0.546246 0.500264 0.564912 +v 0.542679 0.565261 0.588565 +v 0.542885 0.520728 0.572420 +v 0.543696 0.505039 0.566662 +v 0.545344 0.590018 0.588464 +v 0.544297 0.521928 0.568692 +v 0.542189 0.690627 0.624110 +v 0.541855 0.634385 0.610713 +v 0.545739 0.630125 0.619891 +v 0.546087 0.688613 0.635114 +v 0.545515 0.692355 0.612405 +v 0.555131 0.637997 0.596950 +v 0.545370 0.636690 0.600766 +v 0.561378 0.587108 0.604306 +v 0.565457 0.630896 0.619590 +v 0.554671 0.608862 0.615991 +v 0.555785 0.632187 0.624086 +v 0.553407 0.586056 0.607260 +v 0.555634 0.693780 0.608197 +v 0.566665 0.689633 0.634461 +v 0.556536 0.688711 0.638799 +v 0.569867 0.692016 0.623280 +v 0.565915 0.693390 0.611838 +v 0.565017 0.637720 0.600547 +v 0.568863 0.632848 0.609732 +v 0.564321 0.589058 0.596399 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vt 0.5354 0.1581 +vn 0.6852 -0.1796 0.7058 +vn 0.6889 -0.2069 0.6947 +vn 0.9989 -0.0083 0.0452 +vn 0.9996 -0.0118 0.0261 +vn 0.7310 0.1582 -0.6637 +vn 0.0184 0.2187 -0.9756 +vn 0.7510 0.1402 -0.6452 +vn -0.7256 -0.2317 0.6479 +vn -0.7110 -0.3104 0.6309 +vn -0.0232 -0.3473 0.9375 +vn -0.0293 -0.2846 0.9582 +vn -0.0137 -0.3726 0.9279 +vn 0.7068 -0.2481 0.6625 +vn 0.0225 0.1978 -0.9800 +vn -0.7513 -0.1764 0.6359 +vn -0.0534 -0.2516 0.9663 +vn -0.9997 -0.0175 -0.0180 +vn -0.7041 0.1271 -0.6986 +vn -0.7228 0.1305 -0.6786 +vn -0.9980 -0.0569 -0.0285 +vn 0.7079 0.1979 -0.6780 +vn 0.6962 0.0086 -0.7178 +vn -0.0007 0.2428 -0.9701 +vn 0.0009 -0.1480 -0.9890 +vn -0.6703 -0.0903 -0.7365 +vn -0.7047 0.0848 -0.7044 +vn -0.7071 0.1103 -0.6984 +vn -0.0105 0.2557 -0.9667 +vn 0.7241 0.1844 -0.6645 +vn -0.9830 -0.1765 -0.0504 +vn -0.8532 -0.5032 -0.1368 +vn -0.6562 -0.5305 0.5365 +vn -0.6905 -0.3904 0.6089 +vn -0.7033 -0.3457 0.6212 +vn -0.9866 -0.1556 -0.0497 +vn 0.9998 -0.0186 -0.0027 +vn 0.0031 -0.7240 0.6897 +vn 0.0716 -0.9429 -0.3251 +vn 0.9175 -0.3843 -0.1025 +vn 0.6886 -0.4410 0.5756 +vn 0.7020 -0.2838 0.6531 +vn 0.9998 -0.0117 0.0182 +vn 0.0070 -0.4036 0.9149 +vn -0.9938 -0.1068 -0.0303 +vn -0.7125 0.1173 -0.6918 +vn -0.0019 -0.4337 0.9010 +vn -0.9905 -0.1325 -0.0371 +vn 0.7033 -0.3457 0.6212 +vn 0.6905 -0.3904 0.6089 +vn 0.9866 -0.1556 -0.0497 +vn 0.9830 -0.1765 -0.0504 +vn 0.6703 -0.0903 -0.7365 +vn 0.7047 0.0848 -0.7044 +vn 0.6562 -0.5305 0.5365 +vn 0.8532 -0.5032 -0.1368 +vn -0.0009 -0.1480 -0.9890 +vn 0.0007 0.2428 -0.9701 +vn -0.6962 0.0086 -0.7178 +vn 0.7071 0.1103 -0.6984 +vn -0.6886 -0.4410 0.5756 +vn -0.0031 -0.7240 0.6897 +vn 0.0019 -0.4337 0.9010 +vn -0.7020 -0.2838 0.6531 +vn 0.9905 -0.1325 -0.0371 +vn 0.7125 0.1173 -0.6918 +vn 0.0105 0.2557 -0.9667 +vn -0.0070 -0.4036 0.9149 +vn -0.7068 -0.2481 0.6625 +vn -0.0716 -0.9429 -0.3251 +vn -0.9998 -0.0117 0.0182 +vn -0.9998 -0.0186 -0.0027 +vn -0.9175 -0.3843 -0.1025 +vn -0.7241 0.1844 -0.6645 +vn -0.7079 0.1979 -0.6780 +vn -0.9989 -0.0083 0.0452 +vn -0.9996 -0.0118 0.0261 +vn -0.6889 -0.2069 0.6947 +vn -0.6852 -0.1796 0.7058 +vn -0.7510 0.1402 -0.6452 +vn -0.0184 0.2187 -0.9756 +vn -0.7310 0.1582 -0.6637 +vn 0.7110 -0.3104 0.6309 +vn 0.7256 -0.2317 0.6479 +vn 0.0232 -0.3473 0.9375 +vn 0.0293 -0.2846 0.9582 +vn 0.0137 -0.3726 0.9279 +vn -0.0225 0.1978 -0.9800 +vn 0.7513 -0.1764 0.6359 +vn 0.0534 -0.2516 0.9663 +vn 0.9997 -0.0175 -0.0180 +vn 0.7228 0.1305 -0.6786 +vn 0.7041 0.1271 -0.6986 +vn 0.9980 -0.0569 -0.0285 +vn 0.9938 -0.1068 -0.0303 +f 2488/2488/2488 2489/2489/2489 2490/2490/2490 +f 2491/2491/2491 2490/2490/2490 2489/2489/2489 +f 2492/2492/2492 2493/2493/2493 2494/2494/2494 +f 2492/2492/2492 2494/2494/2494 2491/2491/2491 +f 2490/2490/2490 2491/2491/2491 2494/2494/2494 +f 2495/2495/2495 2496/2496/2496 2497/2497/2497 +f 2497/2497/2497 2489/2489/2489 2498/2498/2498 +f 2499/2499/2499 2497/2497/2497 2496/2496/2496 +f 2500/2500/2500 2489/2489/2489 2497/2497/2497 +f 2499/2499/2499 2500/2500/2500 2497/2497/2497 +f 2493/2493/2493 2501/2501/2501 2494/2494/2494 +f 2502/2502/2502 2495/2495/2495 2503/2503/2503 +f 2495/2495/2495 2502/2502/2502 2504/2504/2504 +f 2498/2498/2498 2503/2503/2503 2495/2495/2495 +f 2489/2489/2489 2488/2488/2488 2503/2503/2503 +f 2498/2498/2498 2489/2489/2489 2503/2503/2503 +f 2505/2505/2505 2506/2506/2506 2493/2493/2493 +f 2501/2501/2501 2493/2493/2493 2506/2506/2506 +f 2505/2505/2505 2507/2507/2507 2506/2506/2506 +f 2507/2507/2507 2495/2495/2495 2504/2504/2504 +f 2507/2507/2507 2504/2504/2504 2506/2506/2506 +f 2508/2508/2508 2509/2509/2509 2510/2510/2510 +f 2511/2511/2511 2510/2510/2510 2509/2509/2509 +f 2511/2511/2511 2512/2512/2512 2510/2510/2510 +f 2513/2513/2513 2514/2514/2514 2515/2515/2515 +f 2508/2508/2508 2510/2510/2510 2516/2516/2516 +f 2510/2510/2510 2515/2515/2515 2516/2516/2516 +f 2510/2510/2510 2513/2513/2513 2515/2515/2515 +f 2512/2512/2512 2513/2513/2513 2510/2510/2510 +f 2513/2513/2513 2512/2512/2512 2517/2517/2517 +f 2518/2518/2518 2517/2517/2517 2512/2512/2512 +f 2518/2518/2518 2519/2519/2519 2517/2517/2517 +f 2520/2520/2520 2521/2521/2521 2522/2522/2522 +f 2513/2513/2513 2517/2517/2517 2514/2514/2514 +f 2517/2517/2517 2522/2522/2522 2514/2514/2514 +f 2517/2517/2517 2520/2520/2520 2522/2522/2522 +f 2509/2509/2509 2508/2508/2508 2523/2523/2523 +f 2519/2519/2519 2518/2518/2518 2524/2524/2524 +f 2518/2518/2518 2525/2525/2525 2524/2524/2524 +f 2525/2525/2525 2518/2518/2518 2511/2511/2511 +f 2511/2511/2511 2509/2509/2509 2526/2526/2526 +f 2527/2527/2527 2524/2524/2524 2526/2526/2526 +f 2525/2525/2525 2526/2526/2526 2524/2524/2524 +f 2525/2525/2525 2511/2511/2511 2526/2526/2526 +f 2512/2512/2512 2511/2511/2511 2518/2518/2518 +f 2528/2528/2528 2527/2527/2527 2523/2523/2523 +f 2526/2526/2526 2523/2523/2523 2527/2527/2527 +f 2526/2526/2526 2509/2509/2509 2523/2523/2523 +f 2508/2508/2508 2516/2516/2516 2523/2523/2523 +f 2500/2500/2500 2528/2528/2528 2529/2529/2529 +f 2523/2523/2523 2529/2529/2529 2528/2528/2528 +f 2529/2529/2529 2523/2523/2523 2516/2516/2516 +f 2519/2519/2519 2520/2520/2520 2517/2517/2517 +f 2529/2529/2529 2491/2491/2491 2500/2500/2500 +f 2491/2491/2491 2529/2529/2529 2516/2516/2516 +f 2516/2516/2516 2493/2493/2493 2492/2492/2492 +f 2489/2489/2489 2500/2500/2500 2491/2491/2491 +f 2530/2530/2530 2499/2499/2499 2521/2521/2521 +f 2530/2530/2530 2500/2500/2500 2499/2499/2499 +f 2516/2516/2516 2492/2492/2492 2491/2491/2491 +f 2515/2515/2515 2493/2493/2493 2516/2516/2516 +f 2531/2531/2531 2496/2496/2496 2507/2507/2507 +f 2496/2496/2496 2495/2495/2495 2507/2507/2507 +f 2497/2497/2497 2498/2498/2498 2495/2495/2495 +f 2531/2531/2531 2507/2507/2507 2505/2505/2505 +f 2515/2515/2515 2532/2532/2532 2493/2493/2493 +f 2532/2532/2532 2505/2505/2505 2493/2493/2493 +f 2532/2532/2532 2531/2531/2531 2505/2505/2505 +f 2496/2496/2496 2521/2521/2521 2499/2499/2499 +f 2520/2520/2520 2519/2519/2519 2533/2533/2533 +f 2524/2524/2524 2533/2533/2533 2519/2519/2519 +f 2524/2524/2524 2527/2527/2527 2533/2533/2533 +f 2528/2528/2528 2500/2500/2500 2530/2530/2530 +f 2521/2521/2521 2520/2520/2520 2530/2530/2530 +f 2533/2533/2533 2530/2530/2530 2520/2520/2520 +f 2533/2533/2533 2528/2528/2528 2530/2530/2530 +f 2527/2527/2527 2528/2528/2528 2533/2533/2533 +f 2521/2521/2521 2496/2496/2496 2531/2531/2531 +f 2522/2522/2522 2534/2534/2534 2514/2514/2514 +f 2522/2522/2522 2521/2521/2521 2534/2534/2534 +f 2534/2534/2534 2521/2521/2521 2531/2531/2531 +f 2514/2514/2514 2532/2532/2532 2515/2515/2515 +f 2514/2514/2514 2534/2534/2534 2532/2532/2532 +f 2534/2534/2534 2531/2531/2531 2532/2532/2532 +f 2535/2535/2535 2536/2536/2536 2537/2537/2537 +f 2536/2536/2536 2538/2538/2538 2537/2537/2537 +f 2539/2539/2539 2540/2540/2540 2538/2538/2538 +f 2541/2541/2541 2542/2542/2542 2538/2538/2538 +f 2538/2538/2538 2542/2542/2542 2539/2539/2539 +f 2539/2539/2539 2543/2543/2543 2544/2544/2544 +f 2544/2544/2544 2543/2543/2543 2545/2545/2545 +f 2540/2540/2540 2539/2539/2539 2544/2544/2544 +f 2537/2537/2537 2538/2538/2538 2546/2546/2546 +f 2538/2538/2538 2540/2540/2540 2546/2546/2546 +f 2536/2536/2536 2541/2541/2541 2538/2538/2538 +f 2547/2547/2547 2548/2548/2548 2549/2549/2549 +f 2549/2549/2549 2548/2548/2548 2541/2541/2541 +f 2550/2550/2550 2547/2547/2547 2549/2549/2549 +f 2551/2551/2551 2546/2546/2546 2552/2552/2552 +f 2552/2552/2552 2546/2546/2546 2553/2553/2553 +f 2554/2554/2554 2549/2549/2549 2536/2536/2536 +f 2536/2536/2536 2535/2535/2535 2554/2554/2554 +f 2550/2550/2550 2549/2549/2549 2554/2554/2554 +f 2541/2541/2541 2536/2536/2536 2549/2549/2549 +f 2555/2555/2555 2550/2550/2550 2554/2554/2554 +f 2542/2542/2542 2556/2556/2556 2543/2543/2543 +f 2556/2556/2556 2542/2542/2542 2548/2548/2548 +f 2543/2543/2543 2539/2539/2539 2542/2542/2542 +f 2557/2557/2557 2558/2558/2558 2550/2550/2550 +f 2550/2550/2550 2555/2555/2555 2557/2557/2557 +f 2559/2559/2559 2556/2556/2556 2548/2548/2548 +f 2548/2548/2548 2547/2547/2547 2559/2559/2559 +f 2543/2543/2543 2556/2556/2556 2559/2559/2559 +f 2542/2542/2542 2541/2541/2541 2548/2548/2548 +f 2545/2545/2545 2543/2543/2543 2559/2559/2559 +f 2558/2558/2558 2557/2557/2557 2560/2560/2560 +f 2553/2553/2553 2544/2544/2544 2560/2560/2560 +f 2544/2544/2544 2561/2561/2561 2560/2560/2560 +f 2540/2540/2540 2544/2544/2544 2553/2553/2553 +f 2545/2545/2545 2561/2561/2561 2544/2544/2544 +f 2546/2546/2546 2540/2540/2540 2553/2553/2553 +f 2547/2547/2547 2550/2550/2550 2558/2558/2558 +f 2560/2560/2560 2561/2561/2561 2558/2558/2558 +f 2558/2558/2558 2559/2559/2559 2547/2547/2547 +f 2561/2561/2561 2545/2545/2545 2558/2558/2558 +f 2545/2545/2545 2559/2559/2559 2558/2558/2558 +f 2562/2562/2562 2563/2563/2563 2564/2564/2564 +f 2564/2564/2564 2565/2565/2565 2562/2562/2562 +f 2563/2563/2563 2562/2562/2562 2566/2566/2566 +f 2567/2567/2567 2568/2568/2568 2566/2566/2566 +f 2566/2566/2566 2568/2568/2568 2563/2563/2563 +f 2569/2569/2569 2570/2570/2570 2571/2571/2571 +f 2564/2564/2564 2571/2571/2571 2572/2572/2572 +f 2571/2571/2571 2573/2573/2573 2569/2569/2569 +f 2564/2564/2564 2555/2555/2555 2571/2571/2571 +f 2555/2555/2555 2573/2573/2573 2571/2571/2571 +f 2574/2574/2574 2567/2567/2567 2566/2566/2566 +f 2570/2570/2570 2575/2575/2575 2576/2576/2576 +f 2575/2575/2575 2570/2570/2570 2577/2577/2577 +f 2576/2576/2576 2572/2572/2572 2570/2570/2570 +f 2565/2565/2565 2564/2564/2564 2576/2576/2576 +f 2564/2564/2564 2572/2572/2572 2576/2576/2576 +f 2578/2578/2578 2579/2579/2579 2567/2567/2567 +f 2567/2567/2567 2574/2574/2574 2578/2578/2578 +f 2580/2580/2580 2579/2579/2579 2578/2578/2578 +f 2570/2570/2570 2580/2580/2580 2577/2577/2577 +f 2577/2577/2577 2580/2580/2580 2578/2578/2578 +f 2573/2573/2573 2554/2554/2554 2535/2535/2535 +f 2535/2535/2535 2569/2569/2569 2573/2573/2573 +f 2555/2555/2555 2554/2554/2554 2573/2573/2573 +f 2555/2555/2555 2564/2564/2564 2563/2563/2563 +f 2568/2568/2568 2560/2560/2560 2563/2563/2563 +f 2535/2535/2535 2551/2551/2551 2581/2581/2581 +f 2581/2581/2581 2551/2551/2551 2552/2552/2552 +f 2569/2569/2569 2535/2535/2535 2581/2581/2581 +f 2535/2535/2535 2537/2537/2537 2551/2551/2551 +f 2551/2551/2551 2537/2537/2537 2546/2546/2546 +f 2563/2563/2563 2557/2557/2557 2555/2555/2555 +f 2580/2580/2580 2581/2581/2581 2579/2579/2579 +f 2581/2581/2581 2552/2552/2552 2579/2579/2579 +f 2569/2569/2569 2581/2581/2581 2580/2580/2580 +f 2572/2572/2572 2571/2571/2571 2570/2570/2570 +f 2570/2570/2570 2569/2569/2569 2580/2580/2580 +f 2567/2567/2567 2560/2560/2560 2568/2568/2568 +f 2557/2557/2557 2563/2563/2563 2560/2560/2560 +f 2567/2567/2567 2553/2553/2553 2560/2560/2560 +f 2579/2579/2579 2552/2552/2552 2567/2567/2567 +f 2552/2552/2552 2553/2553/2553 2567/2567/2567 diff --git a/vlkx-resources/pkg/01 - Copy.vxp b/vlkx-resources/pkg/01 - Copy.vxp new file mode 100644 index 0000000..0cdadbb Binary files /dev/null and b/vlkx-resources/pkg/01 - Copy.vxp differ diff --git a/vlkx-resources/pkg/01.vxp b/vlkx-resources/pkg/01.vxp new file mode 100644 index 0000000..3e698f5 Binary files /dev/null and b/vlkx-resources/pkg/01.vxp differ diff --git a/vlkx-resources/pkg/index.vxi b/vlkx-resources/pkg/index.vxi new file mode 100644 index 0000000..500af1f --- /dev/null +++ b/vlkx-resources/pkg/index.vxi @@ -0,0 +1 @@ +01.vxp \ No newline at end of file diff --git a/vlkx-resources/shader/SPIRV/basic.frag.spv b/vlkx-resources/shader/SPIRV/basic.frag.spv new file mode 100644 index 0000000..0e7d70f Binary files /dev/null and b/vlkx-resources/shader/SPIRV/basic.frag.spv differ diff --git a/vlkx-resources/shader/SPIRV/basic.vert.spv b/vlkx-resources/shader/SPIRV/basic.vert.spv new file mode 100644 index 0000000..e620da9 Binary files /dev/null and b/vlkx-resources/shader/SPIRV/basic.vert.spv differ diff --git a/vlkx-resources/shader/SPIRV/rt.stage1.frag.spv b/vlkx-resources/shader/SPIRV/rt.stage1.frag.spv new file mode 100644 index 0000000..77f6fea Binary files /dev/null and b/vlkx-resources/shader/SPIRV/rt.stage1.frag.spv differ diff --git a/vlkx-resources/shader/SPIRV/rt.stage1.vert.spv b/vlkx-resources/shader/SPIRV/rt.stage1.vert.spv new file mode 100644 index 0000000..098ddba Binary files /dev/null and b/vlkx-resources/shader/SPIRV/rt.stage1.vert.spv differ diff --git a/vlkx-resources/shader/SPIRV/rt.stage2.frag.spv b/vlkx-resources/shader/SPIRV/rt.stage2.frag.spv new file mode 100644 index 0000000..3d3bc48 Binary files /dev/null and b/vlkx-resources/shader/SPIRV/rt.stage2.frag.spv differ diff --git a/vlkx-resources/shader/SPIRV/rt.stage2.vert.spv b/vlkx-resources/shader/SPIRV/rt.stage2.vert.spv new file mode 100644 index 0000000..01bc53f Binary files /dev/null and b/vlkx-resources/shader/SPIRV/rt.stage2.vert.spv differ diff --git a/vlkx-resources/shader/SPIRV/rt.stage3.frag.spv b/vlkx-resources/shader/SPIRV/rt.stage3.frag.spv new file mode 100644 index 0000000..3d01c6e Binary files /dev/null and b/vlkx-resources/shader/SPIRV/rt.stage3.frag.spv differ diff --git a/vlkx-resources/shader/SPIRV/rt.stage3.vert.spv b/vlkx-resources/shader/SPIRV/rt.stage3.vert.spv new file mode 100644 index 0000000..a93f95d Binary files /dev/null and b/vlkx-resources/shader/SPIRV/rt.stage3.vert.spv differ diff --git a/vlkx-resources/shader/basic.frag b/vlkx-resources/shader/basic.frag new file mode 100644 index 0000000..db7f6f5 --- /dev/null +++ b/vlkx-resources/shader/basic.frag @@ -0,0 +1,9 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout (location = 0) in vec3 fragColor; +layout (location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0f); +} \ No newline at end of file diff --git a/vlkx-resources/shader/basic.vert b/vlkx-resources/shader/basic.vert new file mode 100644 index 0000000..64500f8 --- /dev/null +++ b/vlkx-resources/shader/basic.vert @@ -0,0 +1,20 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout (binding = 0) uniform UniformBufferObject{ + mat4 model; + mat4 view; + mat4 proj; +} ubo; + +layout (location = 0) in vec3 inPosition; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec3 inColor; +layout (location = 3) in vec2 inUV; + +layout (location = 0) out vec3 fragColor; + +void main() { + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); + fragColor = inColor; +} \ No newline at end of file diff --git a/vlkx-resources/shader/compileShaders.bat b/vlkx-resources/shader/compileShaders.bat new file mode 100644 index 0000000..5a91861 --- /dev/null +++ b/vlkx-resources/shader/compileShaders.bat @@ -0,0 +1,5 @@ +@echo off +echo Compiling GLSL shaders to SPIR-V Binary +for /r %%i in (*.vert;*.frag) do %VULKAN_SDK%\Bin\glslangValidator.exe -V "%%i" -o "%%~dpiSPIRV\%%~nxi".spv + +PAUSE \ No newline at end of file diff --git a/vlkx-resources/x64/VFFEdit/vlkx-resources.exe.recipe b/vlkx-resources/x64/VFFEdit/vlkx-resources.exe.recipe new file mode 100644 index 0000000..76f3794 --- /dev/null +++ b/vlkx-resources/x64/VFFEdit/vlkx-resources.exe.recipe @@ -0,0 +1,11 @@ + + + + + C:\Users\nurgi\Documents\vlkx\x64\VFFEdit\vlkx-resources.exe + + + + + + \ No newline at end of file diff --git a/vlkx-resources/x64/VFFEdit/vlkx-resources.log b/vlkx-resources/x64/VFFEdit/vlkx-resources.log new file mode 100644 index 0000000..6f650eb --- /dev/null +++ b/vlkx-resources/x64/VFFEdit/vlkx-resources.log @@ -0,0 +1,7 @@ + "{0} -> {1} (Partial -> Full PDB)" + System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list. + at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args) + at System.String.FormatHelper(IFormatProvider provider, String format, ParamsArray args) + at System.String.Format(IFormatProvider provider, String format, Object[] args) + at Microsoft.Build.Framework.LazyFormattedBuildEventArgs.FormatString(CultureInfo culture, String unformatted, Object[] args) +EXEC : fatal error CMF1106: failed to open input PDB file for reading (PDB error code = 4) diff --git a/vlkx-resources/x64/VFFEdit/vlkx-resources.tlog/vlkx-resources.lastbuildstate b/vlkx-resources/x64/VFFEdit/vlkx-resources.tlog/vlkx-resources.lastbuildstate new file mode 100644 index 0000000..6a18dda --- /dev/null +++ b/vlkx-resources/x64/VFFEdit/vlkx-resources.tlog/vlkx-resources.lastbuildstate @@ -0,0 +1,2 @@ +PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.30.30705:TargetPlatformVersion=10.0.19041.0: +VFFEdit|x64|C:\Users\nurgi\Documents\vlkx\|