
.. _program_listing_file_Src_GraphicsEngineVulkan_scene_AsyncModelParse.ixx:

Program Listing for File AsyncModelParse.ixx
============================================

|exhale_lsh| :ref:`Return to documentation for file <file_Src_GraphicsEngineVulkan_scene_AsyncModelParse.ixx>` (``Src/GraphicsEngineVulkan/scene/AsyncModelParse.ixx``)

.. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS

.. code-block:: cpp

   module;
   #include <atomic>
   #include <memory>
   #include <string>
   #include <thread>
   
   export module kataglyphis.vulkan.async_model_parse;
   
   import kataglyphis.vulkan.gltf_loader;
   import kataglyphis.vulkan.obj_loader;
   import kataglyphis.vulkan.model_file_kind;
   
   export namespace Kataglyphis {
   
   class AsyncModelParse
   {
     public:
       AsyncModelParse() = default;
       AsyncModelParse(const AsyncModelParse &) = delete;
       AsyncModelParse &operator=(const AsyncModelParse &) = delete;
   
       ~AsyncModelParse() { waitForCompletion(); }
   
       void start(const std::string &modelFile)
       {
           waitForCompletion();
   
           finished.store(false, std::memory_order_release);
           succeeded.store(false, std::memory_order_release);
           loader.reset();
           gltfLoader.reset();
           path = modelFile;
   
           // Dispatch by extension. The OBJ path is unchanged; glTF gets a parallel
           // one so both load off the render thread.
           if (isGltfModelPath(modelFile)) {
               gltfLoader = std::make_unique<GltfLoader>();// device-free
               worker = std::thread([this] {
                   const bool ok = gltfLoader->parseCpu(path);
                   succeeded.store(ok, std::memory_order_release);
                   finished.store(true, std::memory_order_release);
               });
           } else {
               loader = std::make_unique<ObjLoader>();// device-free
               worker = std::thread([this] {
                   const bool ok = loader->parseCpu(path);
                   succeeded.store(ok, std::memory_order_release);
                   // Release LAST: a reader that sees finished == true must also see
                   // every write the parse made, including `succeeded`.
                   finished.store(true, std::memory_order_release);
               });
           }
       }
   
       [[nodiscard]] bool isRunning() const { return worker.joinable() && !isFinished(); }
   
       [[nodiscard]] bool isFinished() const { return finished.load(std::memory_order_acquire); }
   
       [[nodiscard]] bool wasSuccessful() const { return succeeded.load(std::memory_order_acquire); }
   
       std::unique_ptr<ObjLoader> takeResult()
       {
           waitForCompletion();
           if (!succeeded.load(std::memory_order_acquire)) {
               loader.reset();
               return nullptr;
           }
           return std::move(loader);
       }
   
       [[nodiscard]] bool parsedGltf() const { return gltfLoader != nullptr; }
   
       std::unique_ptr<GltfLoader> takeGltfResult()
       {
           waitForCompletion();
           if (!succeeded.load(std::memory_order_acquire)) {
               gltfLoader.reset();
               return nullptr;
           }
           return std::move(gltfLoader);
       }
   
       void waitForCompletion()
       {
           if (worker.joinable()) { worker.join(); }
       }
   
     private:
       std::thread worker;
       std::atomic<bool> finished{ false };
       std::atomic<bool> succeeded{ false };
       std::unique_ptr<ObjLoader> loader;
       std::unique_ptr<GltfLoader> gltfLoader;
       std::string path;
   };
   
   }// namespace Kataglyphis
