@startuml
title Main Execution
caption 
  //**Main execution from the run function in the entrypoint**//
  //**This dictates basic flow of the vulkan boilerplate system. **//
endcaption

://**main()**//; <<procedure>>
://**run()**//; <<procedure>>
split
://**initWindow()**//; <<procedure>>
:glfwInit();
:window = glfwCreateWindow(...);
note left
  //Create window and initialize default settings//
endnote
:glfwSetWindowUserPointer(...);
note left 
  //Set the user-defined pointer of the window//
endnote
:glfwSetFramebufferSizeCallback(...);
note left 
  //This is a callback to resizing of the window//
  //we call and set a bool to true, which we get//
  //and rebuild the swap chain when true.//
endnote
stop
split again
://**initVulkan()**//; <<procedure>>
split
://**createInstance()**//; <<procedure>>
split
:**Debug**::checkUnavailableValidationLayers();
:**VkApplicationInfo** appInfo{};
://set appInfo data, Vulkan version,// 
//Engine version and name, and title//;
:**VkApplicationCreateInfo** createInfo{};
:createInfo.pApplicationInfo = &appInfo;
:Debug::vulkanDebugSetup(createInfo, vulkaninstance);
end split
split again
:**Debug**::setupDebugMessenger(VkInstance&);
note right: Setup debug messenger, print data to console

partition "**DeviceControl**" {
:createSurface(...);
note right
  This function handles Window System Integration 
  automatically across platforms based on build environment.
  ====
  //Basically, this is an abstraction of the Window across platforms//
end note
  :pickPhysicalDevice(...);
  note right
    Enumerate through GPU's in the 
    system and choose a compatible one.
    ====
    //in the future, this should choose the BEST// 
    //GPU, not just the first one that is compatible..//
  end note
  :createLogicalDevice(...);
  note right
    Logical devices interface with the 
    physical device and defines queues
  end note
  :createSwapChain(...);
  note right
    Swap Chains are used to handle buffer ownership 
    infrastructure. Being platform agnostic has its 
    complications, this is a perfect example.
    This process is HEAVILY documented.
  end note
  :createImageViews(...);
  note right
    This is a cool function, quite a simple
    description of images that will be shown on the
    screen! It also determines //how// to access the image
  end note
}

:**Graphics**::createRenderPass(...);
note right
  This is pretty simple, it sets up the image bit depth 
  and the color bit depth! Basically, the format of the
  displayed images, simple, but important!
end note
:**Buffers**::createDescriptorSetLayout();
note right 
  This function creates a table of pointers to the stored
  data that we want, in this case it would be pointing to 
  pre-programmed model view and projection values, and 
  a time variable.
end note
partition "**Graphics**" {
  :createGraphicsPipeline(...);
  note right
    This is a complex function that goes through every 
    step of the render pipeline and sets the settings we
    desire for each step! **HEAVILY** documented.
  end note
  :createCommandPool(...);
  note right
    Commands in Vulkan are not executed using function calls 
    You have to record the ops you want to perform to command 
    buffer objects, pools manage the memory used for buffers.
  end note
}

:**Texture**::createDepthResources();
note right 
  This function sets up the image views and sets for the 
  depth testing buffer to handle objects above or below
  other objects!
end note
:**Graphics**::createFramebuffers(...);
note right
  This function creates framebuffers for all the images 
  that are queued to be displayed, very important!
end note

partition "**Texture**" {
  :createTextureImage();
  note right 
    This function imports the pixels from an image, puts them
    into a buffer, and copies them from memory into a texture!
    A bit complicated because we are moving and freeing lots of
    memory, but quite useful.
  end note
  :createTextureImageView();
  note right
    This function creates a image view for the texture, just 
    builds a struct holding information about the texture, like
    layers, mip levels, and etc.
  end note
  :createTextureSampler();
  note right
    This function is **incredibly** important. This builds a 
    texture sampler, information about what to do with the 
    texture once its created. This defines settings like 
    //UVW mode//, //Filtering//, //Anisotropy//, and 
    //Mipmap modes//
  end note
}
partition "**Model**" {
  :loadModel();
  note right 
    Exactly what it sounds like, as of now, call our function 
    to load .OBJ files with STB. Obviously want to support FBX 
    in the future but the format is quite complex.
    This function simply loads vertices and indices into the 
    arrays to be parsed!
  end note
}
partition "**Buffers**" {
  :createVertexBuffer();
  note right 
    Vertex buffers are incredibly useful, in essence,
    you can read data from memory as vertex input to the
    vertex shader rather than hardcoded data!
  end note
  :createIndexBuffer();
  note right
    Index buffers are cool, basically, you can store
    some vertices that would normally be duplicated 
    at corners to triangulate. this saves cycles at 
    scale, complex objects rejoice!
  end note
  :createUniformBuffer();
  note right
    Map the buffer data to memory (The struct) as a pointer
    we can use this as a reference of where to write data to 
    when the fence lets us write data.
    (see **recordCommandBuffer()**).
  end note
  :createDescriptorPool();
  note right
    Here we create a pool to manage the memory and allocate
    space for the descriptor sets! Very useful and the same 
    structure as command buffers & pools.
  end note
  :createDescriptorSetLayout();
  note right
    //Descriptor set **layouts** specify the types of resources accessible//
    //by the graphical pipeline. A descriptor set is the actual buffer//
    //or resource that gets bound to descriptors and passed in.//
    These differ from Vertex & Index buffers, as they are not unique
    to the graphics pipeline. Specification of compute vs. graphics is 
    therefore necessary. (see **createDescriptorSets()**)
  end note
}
:**Graphics**::createCommandBuffer();
note right 
  This is the partner to the commandPool creator, 
  storing the commands we wish to perform whilst 
  waiting in a queue. These are very efficient.
end note
:**RenderPresent**::createSyncObject();
note right
  This is **HEAVILY** documented, create Semaphores
  and Fences, for halting and starting execution, basically 
  a traffic controller for the GPU.
end note
end split
stop
split again
repeat ://**mainLoop()**//; <<procedure>>
  :glfwPollEvents();
  :RenderPresent::drawFrame();
repeat while (!glfwWindowShouldClose(...))
  :vkDeviceWaitIdle(...);
stop
split again
://**cleanup()**//; <<procedure>>
note right
  //This function initiates a series of shutdown//
  //destroy functions, safely stopping execution//;
endnote
:return EXIT_SUCCESS;
stop
end split

@enduml
