{.experimental: "parallel".}

import ../scene/[ scene_object
                      , scene_utils
                      , scene_record
                     ] 

, ../vk/[ vulkan
        , vkTypes
        , vulkan_record
        , graphics_pipeline
        , pipeline_record 
        , buffer
        , gpu
        , vulkan_utils
        ]

, ../drawable/[ shape_object
              , shape_types 
              , plane 
              , colors
              , grid
              ]
, ../drawable/text as mText

, ../deshn_entity/[ being 
                  , actions 
                  ]

, glm
, strUtils
, ../wain/keyboard 
, ../camera 

, std/tables
, ../state_machine

, options 

proc load*( vulkan_record: var Vulkan_Record
                , pipeline_record: Pipeline_Record
                , intro: var Scene
                , scene_record: var Scene_Record
                ) = discard
 
 #intro.the_deshn_being("protag").main_state_machine.current_state = some Main_Deshn_Being_States.Idle

proc input*( vulkan_record: var Vulkan_Record
                  , sr: var Scene_Record
                  ) = discard 


proc update*( vulkan_record: var Vulkan_Record
                    , intro: var Scene
                    , sr: var Scene_Record
                    , fps: string
                    ) =  
 
 var 
  protag = intro.the_deshn_being("protag")
#  plane = intro.the_plane("plane0")
 
 #[ if WAIN_Key.K3.is_down_or_held: 
  plane.shape.camera.position_is vec3f(  plane.shape.camera.position.xy
                                       , plane.shape.camera.position.z + 0.1
                                       )
 if WAIN_Key.K4.is_down_or_held: 
  plane.shape.camera.position_is vec3f(  plane.shape.camera.position.xy
                                       , plane.shape.camera.position.z - 0.1
                                       ) ]#
 
 
 if WAIN_Key.Comma.is_up and 
    WAIN_Key.O.is_up     and 
    WAIN_Key.A.is_up     and 
    WAIN_Key.E.is_up     and 
    not protag.recovering:  
  protag.current_state_is Not_Moving
 
 if not protag.deshn_pool_is_full and 
     not protag.recovering: 
  # echo "NOT moving, adding."
   protag.add_amount_to_deshn_pool 0.03
 else: 
  #echo "can't add because: " , protag.deshn_pool_is_full, " <> ", protag.recovering
  discard 
 if protag.recovering:
   #echo "RECOVERING: ", protag.current_deshn_pool_recovery_pool
   protag.add_amount_to_recovery_pool 0.01   


proc build_command_buffers*( draw_command_buffer: var VkCommandBuffer
                           , scene: var Scene  
                           , graphics_pipeline: Graphics_Pipeline
                           , descriptor_set: VkDescriptorSet
                           , gpu: GPU
                           , vulkan_record: var Vulkan_Record 
                           , indirect_command_buffer: var Buffer
                           ) =
 var
  command_buffer_info = VkCommandBufferBeginInfo(sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO)
  scissor: VkRect2D 
  clearValues: array[2,VkClearValue]
  render_pass_info: VkRenderPassBeginInfo
  offsets = VkDeviceSize 0
  viewport = VkViewport( width: float32 vulkan_record.swapchain.current_extent.width
                       , height: float32 vulkan_record.swapchain.current_extent.height
                       , minDepth: 0.0f
                       , maxDepth: 1.0f
                       )
  
 scissor.extent.width = uint32 vulkan_record.swapchain.current_extent.width
 scissor.extent.height = uint32 vulkan_record.swapchain.current_extent.height
 scissor.offset.x = 0
 scissor.offset.y = 0

 clearValues[0].color = VkClearColorValue(float32: [0f, 0f, 0f, 1f])
 clearValues[1].depth_stencil = VkClearDepthStencilValue(depth: 1.0f, stencil: 0 )
 
 render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
 render_pass_info.pNext = nil
 render_pass_info.renderArea.offset.x = 0
 render_pass_info.renderArea.offset.y = 0
 render_pass_info.renderArea.extent.width = uint32 vulkan_record.swapchain.current_extent.width
 render_pass_info.renderArea.extent.height = uint32 vulkan_record.swapchain.current_extent.height
 render_pass_info.clearValueCount = 2
 render_pass_info.pClearValues = addr clearValues[0]
 #render_pass_info.render_pass = scene.render_pass
  
 for i in 0 .. vulkan_record.draw_command_buffers.len:
  render_pass_info.framebuffer = vulkan_record.frame_buffers[i]
  discard vkBeginCommandBuffer( vulkan_record.draw_command_buffers[i]
                              , addr command_buffer_info
                              )
 
  vkCmdBeginRenderPass( vulkan_record.draw_command_buffers[i]
                      , addr render_pass_info
                      , VK_SUBPASS_CONTENTS_INLINE
                      )
  
  vkCmdSetViewport( vulkan_record.draw_command_buffers[i]
                  , 0
                  , 1
                  , addr vulkan_record.current_viewport
                  )
  
  vkCmdSetScissor( vulkan_record.draw_command_buffers[i]
                 , 0
                 , 1
                 , addr scissor
                 )
 
  vkCmdBindDescriptorSets( vulkan_record.draw_command_buffers[i]
                         , VK_PIPELINE_BIND_POINT_GRAPHICS
                         , graphics_pipeline.pipeline_layout
                         , 0
                         , 1
                         , addr descriptor_set
                         , 0, nil
                         )
 
  vkCmdBindPipeline( vulkan_record.draw_command_buffers[i]
                  , VK_PIPELINE_BIND_POINT_GRAPHICS
                  , graphics_pipeline.pipeline
                  )
 
  vkCmdSetLineWidth(vulkan_record.draw_command_buffers[i], 1)
 
  vkCmdBindVertexBuffers( vulkan_record.draw_command_buffers[i]
                       , 0
                       , 1
                       , addr scene.vertex_buffer.vk_buffer
                       , addr offsets
                       )
 
  vkCmdBindIndexBuffer( vulkan_record.draw_command_buffers[i]
                     , scene.index_buffer.vk_buffer
                     , VkDeviceSize 0
                     , VK_INDEX_TYPE_UINT32
                     )

#[  vkCmdPushConstants( draw_command_buffer
                   , graphics_pipeline.pipeline_layout
                   , VKShaderStageFlags VK_SHADER_STAGE_VERTEX_BIT.ord or VK_SHADER_STAGE_FRAGMENT_BIT.ord
                   , uint32 0
                   , uint32 sizeof Shape_Pushes
                   , cast[pointer] ( addr push_constants )
                   ) ]#

  if gpu.features.multiDrawIndirect.bool:
   vkCmdDrawIndexedIndirect( vulkan_record.draw_command_buffers[i]
                           , indirect_command_buffer.vk_buffer
                           , VkDeviceSize 0
                           , uint32 scene.indirect_commands.len
                           , uint32 sizeof(VkDrawIndexedIndirectCommand)
                           )
  
  vkCmdEndRenderPass( vulkan_record.draw_command_buffers[i]
                    )
  
  discard vkEndCommandBuffer( vulkan_record.draw_command_buffers[i]
                            )
 
 #shape.camera.updateAR(60, vulkan_record.swapchain.current_extent.width.float / float vulkan_record.swapchain.current_extent.height ) 
 
 #vulkan_record.readyFrame = true

proc build_scene*( vulkan_record: var Vulkan_Record
          , scene: var Scene
          , pipeline_record: Pipeline_Record
          ) = 

 
 vulkan_record.readyFrame = true