7P4O3MAXN2LHNTNUNJXGMAG3RWHFDQQAE3VPWKIB4ERINQNSD4BAC
, vk/[ vulkan
, vkTypes
, vulkan_record
, pipeline_record
]
, scenes/[ scene_object
, scene_utils
, scene_record
, main_scenes
]
import drawable/text as mtext
import scenes/intro as sIntro
import scenes/title as sTitle
#TODO: Figure out a way to auto-sync or get rid of current_scene and the_main_scene
# so we only need to worry about one to know and go to the proper scene
proc load*( sr: var Scene_Record
, rec: var Vulkan_Record
, pipeline_record: Pipeline_Record
) = discard
#sTitle.load rec, title
#sIntro.load rec, intro
#case sr.the_main_scene
#of Main_Scene_Enum.Intro: sr.current_scene = sr.get_scene "intro"
#of Main_Scene_Enum.Title: sr.current_scene = sr.get_scene "title"
proc update*( sr: var Scene_Record
, rec: var Vulkan_Record
, fps: string
, tick_rate: float32
) = discard
#[ case sr.the_main_scene
of Main_Scene_Enum.Title:
sr.current_scene = sr.get_scene "title"
sTitle.update rec, sr.current_scene[]
of Main_Scene_Enum.Intro:
sr.current_scene = sr.get_scene "intro"
sIntro.update rec, sr.current_scene[], sr, fps ]#
proc input*( sr: var Scene_Record
, rec: var Vulkan_Record
) = discard
#[ case sr.the_main_scene
of Main_Scene_Enum.Title: sTitle.input rec, sr
of Main_Scene_Enum.Intro: sIntro.input rec, sr ]#
#of Main_Scene_Enum.alive: discard #alive.input(w, hero)
proc show*( sr: Scene_Record
, rec: var Vulkan_Record
, pipeline_record: Pipeline_Record
) = discard
#[ case sr.the_main_scene
of Main_Scene_Enum.Title:
sTitle.show rec, sr.current_scene[]
of Main_Scene_Enum.Intro: sIntro.show( rec
, sr.current_scene[]
, pipeline_record
) ]#
# of Main_Scene_Enum.alive: discard #alive.input(w, hero)
proc prepFrame*(rec: var Vulkan_Record
, sr: var Scene_Record
, pipeline_record: Pipeline_Record
) =
discard vkAcquireNextImageKHR( rec.vk_device
, rec.swapChain.handle
, uint64.high
, rec.presentCompleteSemaphore
, VkFence 0
, addr rec.currentFrameBuffer
)
discard vkWaitForFences(rec.vk_device, 1, addr rec.fences[rec.currentFrameBuffer], VKBool32 true, uint64.high)
discard vkResetFences(rec.vk_device, 1, addr rec.fences[rec.currentFrameBuffer])
sr.show rec, pipeline_record
proc submitFrame*( current_frame_buffer: uint32
, render_complete_semaphore: VkSemaphore
, queue: VkQueue
#, scene: var Scene
, present_info: var VkPresentInfoKHR
) =
#for shape in scene.shapes.mitems:
#if shape.changed: rec.vk_device.updateCamera shape
#[ for text in scene.texts.mitems:
if text.changed:
text.updateCamera ]#
# THE M A G I C (presenting) queuePresent
#[ var presentInfo: VkPresentInfoKHR
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR
presentInfo.pNext = nil
presentInfo.swapchainCount = 1
presentInfo.pSwapchains = addr rec.swapChain.swapChainKHR ]#
present_info.pImageIndices = addr current_frame_buffer #rec.currentFrameBuffer
# Check if a wait semaphore has been specified to wait for
# before presenting the image
if (render_complete_semaphore.int != 0):
presentInfo.pWaitSemaphores = addr render_complete_semaphore
presentInfo.waitSemaphoreCount = 1
#TODO: WHY DOES THIS MEMORY LEAK EVERY FRAME
var preres = vkQueuePresentKHR( queue
, addr presentInfo
)
#if preres == VK_SUBOPTIMAL_KHR: quit "bad vkQueuePresentKHR"
# rec.windowResize scene
# scene.rebuild rec
# discard vkDeviceWaitIdle rec.vk_device
# rec.readyFrame = true
proc sendFrame*(rec: var Vulkan_Record
, sr: var Scene_Record
, pipeline_record: Pipeline_Record
, present_info: var VkPresentInfoKHR
) =
if rec.readyFrame:
rec.prepFrame sr, pipeline_record
var
waitStageMask = VkPipelineStageFlags VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
submitInfo = VkSubmitInfo(
sType: VK_STRUCTURE_TYPE_SUBMIT_INFO
, pWaitDstStageMask: addr waitStageMask
, pWaitSemaphores: addr rec.presentCompleteSemaphore
, waitSemaphoreCount: 1
, pSignalSemaphores: addr rec.renderCompleteSemaphore
, commandBufferCount: 1
, pCommandBuffers: addr rec.draw_command_buffers[rec.currentFrameBuffer]
, signalSemaphoreCount: 1
)
discard vkQueueSubmit( rec.queue
, 1
, submitInfo.addr
, rec.fences[rec.currentFrameBuffer]
)
submitFrame( rec.currentFrameBuffer
, rec.renderCompleteSemaphore
, rec.queue
, present_info
)
#rec.readyFrame = false
import wain/window
{.experimental: "parallel".}
import 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
, ../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
) =
var
protag_shape = a_shape( vulkan_record
, pipeline_record
, intro.render_pass
, intro.current_entity_id
, 3
, "protag_tri"
, theSize = vec2f( 4.5
, 4.5
)
, being_color = silver_blue
, deshn_color = yellow
, camera_type = Camera_Kind.Perspective
, hollow = false
)
#[ intro.add Plane( shape: a_shape( vulkan_record
, pipeline_record
, intro.render_pass
, intro.current_entity_id
, 4
, "plane0_quad"
, theSize = vec2f( 80
, 40
)
, being_color = dark_purple
, deshn_color = yellow
, camera_type = Camera_Kind.Perspective
, hollow = false
)
, name: "plane0"
, grid: a_dynamic_grid( 10
, 10
, vulkan_record
, intro.render_pass
, pipeline_record
, intro.current_entity_id
, parent_buffer
)
) ]#
intro.add( a_deshn_being( shape = protag_shape
, name = "protag"
)
)
#[ intro.the_deshn_being("protag").move_to( (vulkan_record.swapchain.current_extent.width.int / 2).float32
, (vulkan_record.swapchain.current_extent.height.int / 2).float32
)
intro.the_plane("plane0").move_to( (vulkan_record.swapchain.current_extent.width.int / 2).float32
, (vulkan_record.swapchain.current_extent.height.int / 2).float32
) ]#
intro.the_deshn_being("protag").shape.camera.position_is vec3f(0.0,0.0,-50.0)
# intro.the_shape("plane0_quad").camera.position_is vec3f(0.0,0.0,-50.0)
scene_record.add_scene( addr intro
, "intro"
)
intro.the_deshn_being("protag").main_state_machine.current_state = some Main_Deshn_Being_States.Idle
intro.indirect_commands.setLen intro.current_entity_id
for i in 0..intro.current_entity_id - 1:
intro.indirect_commands[i].instanceCount = 1
intro.indirect_commands[i].firstInstance = 1
intro.indirect_commands[i].firstIndex = 0
intro.indirect_commands[i].indexCount = 1
#echo intro.the_deshn_being("protag").main_state_machine.transitions
prepare_vertices( intro
, vulkan_record.vk_device
, vulkan_record.gpu.memory_properties
, vulkan_record.command_pool
, vulkan_record.queue
, vulkan_record.master_vertex_buffer
, vulkan_record.master_index_buffer
)
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")
protag.shape.camera.position_is vec3f( protag.shape.camera.position.xy
, protag.shape.camera.position.z + 0.1
)
protag.shape.camera.position_is vec3f( protag.shape.camera.position.xy
, protag.shape.camera.position.z - 0.1
)
plane.shape.camera.position_is vec3f( plane.shape.camera.position.xy
, plane.shape.camera.position.z + 0.1
)
plane.shape.camera.position_is vec3f( plane.shape.camera.position.xy
, plane.shape.camera.position.z - 0.1
) ]#
protag.move_up 1
protag.move_down 1
protag.move_left 1
protag.move_right 1
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 show*( vulkan_record: var Vulkan_Record
, scene: var Scene
, pipeline_record: Pipeline_Record
) =
vulkan_record.readyFrame = true
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
if WAIN_Key.E.is_down_or_held:
if WAIN_Key.A.is_down_or_held:
if WAIN_Key.O.is_down_or_held:
if WAIN_Key.Comma.is_down_or_held:
if WAIN_Key.K4.is_down_or_held:
#[ if WAIN_Key.K3.is_down_or_held:
if WAIN_Key.K2.is_down_or_held:
if WAIN_Key.K1.is_down_or_held:
, ../wain/keyboard
import tables
, ../drawable/[ shape_object
, textTypes
, plane
]
, ../deshn_entity/[ being
]
, ../vk/[ vulkan
, vkTypes
, depth_stencil
, buffer
]
type
SceneObj = object of RootObj
device*: ptr VkDevice
entities*: TableRef[string, int]
shapes*: seq[Shape]
#texts*: seq[SDFText]
deshn_beings*: seq[Deshn_Being]
planes*: seq[Plane]
current_entity_id*: int
render_pass*: VkRenderPass
depth_stencil*: Depth_Stencil
render_pass_begin_info*: VkRenderPassBeginInfo
scissor*: VkRect2D
vertex_buffer*: Buffer
index_buffer*: Buffer
staging_vertex_buffer*: Buffer
staging_index_buffer*: Buffer
# TODO: a better way , instead of having to redundantly copy vertices and indices
the_vertices*: seq[float32]
the_indices*: seq[uint32]
indirect_commands*: seq[VkDrawIndexedIndirectCommand]
Scene* = ref object of SceneObj
import scene_object
, main_scenes
import std/tables
type
Scene_Record_Object = object of RootObj
current_scene*: ptr Scene
main_scene_table*: Table[string, ptr Scene]
Scene_Record* = ref object of Scene_Record_Object
proc a_scene_record*( the_main_scene: Main_Scene_Enum
, current_scene: ptr Scene = nil
): Scene_Record =
result = Scene_Record( current_scene: current_scene
, main_scene_table: initTable[string, ptr Scene]()
)
proc add_scene*( scene_record: var Scene_Record
, scene: ptr Scene
, scene_name: string
) =
scene_record.main_scene_table[scene_name] = scene
proc get_scene*( scene_record: var Scene_Record
, scene_name: string
): ptr Scene =
scene_record.main_scene_table[scene_name]
{.experimental: "codeReordering".}
{.deadCodeElim: on.}
#TODO: REBUILD render_Pass_begin_info on window size change
import ../vk/[ vulkan_record
, vulkan_utils
, vulkan
, depth_stencil
, swapchain
, buffer
]
, scene_object
, scene_record
, ../deshn_entity/[ being
]
, ../drawable/[ shape_object
, textTypes
, plane
]
]
, std/[ tables
, bitops
]
, glm
proc a_scene*( vk_record: var Vulkan_Record
): Scene =
result = Scene()
result.entities = newTable[string, int]()
proc theIds*(scene: Scene): seq[int] =
for t in scene.shapes: result.add t.id
proc theNames*(scene: Scene): seq[string] =
for t in scene.shapes: result.add t.name
proc the_shape*( scene: var Scene
, id: int
, name: string
): var Shape =
for t in scene.shapes.mitems:
if t.id == id: return t
quit("ERROR: Entity[SHAPE] not found: " & name & ": id" & $id)
proc the_shape*( scene: var Scene
, name: string
): var Shape =
scene.the_shape scene.entities[name], name
proc the_deshn_being*( scene: var Scene
, id: int
, name: string
): var Deshn_Being =
for t in scene.deshn_beings.mitems:
if t.id == id: return t
quit("ERROR: Entity[SHAPE] not found: " & name & ": id" & $id)
proc the_deshn_being*( scene: var Scene
, name: string
): var Deshn_Being =
scene.the_deshn_being scene.entities[name], name
#[ proc the_text*( scene: Scene
, id: int
, name: string
): var SDFText =
#WARNING]: Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]
for t in scene.texts.mitems:
if t.id == id: return t
quit("ERROR: Entity[SDFTEXT] not found: " & name & " / id:" & $id)
proc the_text*( scene: Scene
, name: string
): var SDFText = scene.the_text scene.entities[name], name ]#
# # TODO: need drawable-independent command buffers
# proc build*( vk_record: Vulkan_Record
# , scene: var Scene
# ) =
proc the_plane*( scene: var Scene
, id: int
, name: string
): var Plane =
for t in scene.planes.mitems:
if t.id == id: return t
quit("ERROR: Entity[SHAPE] not found: " & name & ": id" & $id)
proc the_plane*( scene: var Scene
, name: string
): var Plane =
scene.the_plane scene.entities[name], name
proc add*( scene: var Scene
, shape: Shape
) =
#echo "adding: ", sh.name, " ", sh.id
scene.shapes.add shape
scene.entities[shape.name] = shape.id
scene.current_entity_id += 1
scene.the_vertices.add shape.vertices
scene.the_indices.add shape.indices
#[ proc add*( scene: var Scene
, text: SDFText
) =
scene.texts.add text
scene.entities[text.name] = scene.current_entity_id
scene.current_entity_id += 1
for text_vert in text.vertices:
scene.the_vertices.add text_vert.pos.x
scene.the_vertices.add text_vert.pos.y
scene.the_vertices.add text_vert.pos.z
scene.the_vertices.add text_vert.uv.x
scene.the_vertices.add text_vert.uv.y
scene.the_indices.add text.indices
]#
proc add*( scene: var Scene
, deshn_being: Deshn_Being
) =
#echo "adding: ", sh.name, " ", sh.id
scene.deshn_beings.add deshn_being
scene.entities[deshn_being.name] = deshn_being.id
scene.current_entity_id += 1
scene.add deshn_being.shape
proc add*( scene: var Scene
, plane: Plane
) =
#echo "adding: ", sh.name, " ", sh.id
scene.planes.add plane
scene.entities[plane.name] = plane.id
scene.current_entity_id += 1
scene.add plane.shape
proc prepare_vertices*( scene: var Scene
, vk_device: VkDevice
, memory_properties: VkPhysicalDeviceMemoryProperties
, command_pool: VkCommandPool
, queue: VkQueue
, master_vertex_buffer: var Buffer
, master_index_buffer: var Buffer
) =
var
copyCmd: VkCommandBuffer = vk_device.getCommandBuffers(command_pool, true)
copyRegion: VkBufferCopy
data: pointer
#[ copyMem( data, addr scene.the_vertices[0]
, Natural scene.the_vertices.sizeof
)
vkUnmapMemory( vk_device
, scene.staging_vertex_buffer.device_memory
)
discard vkBindBufferMemory( vk_device
, scene.staging_vertex_buffer.vkbuffer
, scene.staging_vertex_buffer.device_memory
, VkDeviceSize 0
)
discard vkBindBufferMemory( vk_device
, scene.vertex_buffer.vkbuffer
, scene.vertex_buffer.device_memory
, VkDeviceSize 0
)
scene.staging_index_buffer = a_vulkan_buffer( vk_device
, memory_properties
, VkBufferUsageFlags VK_BUFFER_USAGE_TRANSFER_SRC_BIT
, VkMemoryPropertyFlags bitor( VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT.ord
, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT.ord
)
, VkDeviceSize scene.the_indices.sizeof
)
scene.index_buffer = a_vulkan_buffer( vk_device
, memory_properties
, VkBufferUsageFlags bitor(VK_BUFFER_USAGE_INDEX_BUFFER_BIT.ord, VK_BUFFER_USAGE_TRANSFER_DST_BIT.ord)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
, VkDeviceSize scene.the_indices.sizeof
)
vk_device.map_memory( scene.staging_index_buffer.device_memory
, data
)
copyMem(data, addr scene.the_indices[0], Natural scene.the_indices.sizeof)
vkUnmapMemory(vk_device, scene.staging_index_buffer.device_memory)
discard vkBindBufferMemory(vk_device, scene.staging_index_buffer.vkbuffer, scene.staging_index_buffer.device_memory, VkDeviceSize 0)
discard vkBindBufferMemory(vk_device, scene.index_buffer.vkbuffer, scene.index_buffer.device_memory, VkDeviceSize 0)
copyRegion.size = VkDeviceSize scene.the_vertices.sizeof
vkCmdCopyBuffer(copyCmd, scene.staging_vertex_buffer.vkbuffer, scene.vertex_buffer.vkbuffer, 1.uint32, addr copyRegion)
copyRegion.size = VkDeviceSize scene.the_indices.sizeof
vkCmdCopyBuffer(copyCmd, scene.staging_index_buffer.vkbuffer, scene.index_buffer.vkbuffer, 1.uint32, addr copyRegion)
# # Flushing the command buffer will also submit it to the queue and
# # uses a fence to ensure that all commands have been executed before returning
vk_device.flushCommandBuffer queue, command_pool, copyCmd
# Destroy staging buffers
# Note: Staging buffer must not be deleted before the copies have been submitted and executed
vkDestroyBuffer( vk_device
, scene.staging_vertex_buffer.vkbuffer
, nil
)
vkFreeMemory( vk_device
, scene.staging_vertex_buffer.device_memory
, nil
)
vkDestroyBuffer( vk_device
, scene.staging_index_buffer.vkbuffer
, nil
)
vkFreeMemory( vk_device
, scene.staging_index_buffer.device_memory
, nil
) ]#
proc cleanup*( vk_record: var Vulkan_Record
, scene: var Scene
) =
discard vkDeviceWaitIdle vk_record.vk_device
# recycle the Pools!
# vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL)
# vkDestroyCommandPool(demo->device, demo->command_pool, NULL);
#should we have an initial "setup command buffer"?
#[ for shape in scene.shapes:
vk_record.vk_device.vkDestroyPipeline(shape.graphicsPipeline.pipeline, nil)
vk_record.vk_device.vkDestroyPipelineLayout(shape.graphicsPipeline.pipelineLayout, nil)
vk_record.vk_device.vkDestroyDescriptorSetLayout(shape.descrSetLayout, nil)
for text in scene.texts:
vk_record.vk_device.vkDestroyPipeline(text.graphicsPipeline.pipeline, nil)
vk_record.vk_device.vkDestroyPipelineLayout(text.graphicsPipeline.pipelineLayout, nil)
vk_record.vk_device.vkDestroyDescriptorSetLayout(text.descrSetLayout, nil) ]#
for i,fb in vk_record.draw_command_buffers:
vkFreeCommandBuffers( vk_record.vk_device
, vk_record.command_pool
, 1
, addr vk_record.draw_command_buffers[i]
)
vk_record.vk_device.vkDestroyRenderPass(scene.render_pass, nil)
, ready_frame: var bool
, scene : var Scene
) =
readyFrame = false
#vk_record.draw_command_buffers.setLen 0
# frame_buffers.setLen 0
proc rebuild_render_pass_info*( vk_record: var Vulkan_Record
, scene: var Scene
) =
var
scissor = VkRect2D( extent: VkExtent2D( width: uint32 vk_record.swapchain.current_extent.width
, height: uint32 vk_record.swapchain.current_extent.height
)
, offset: VkOffset2D( x: 0
, y: 0
)
)
renderPassBeginInfo = VkRenderPassBeginInfo(sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO)
clearValues: array[2,VkClearValue]
clearValues[0].color = VkClearColorValue(float32: [0f, 0f, 0f, 1f])
clearValues[1].depth_stencil = VkClearDepthStencilValue( depth: 1.0f
, stencil: 0
)
renderPassBeginInfo.pNext = nil
renderPassBeginInfo.renderArea.offset.x = 0
renderPassBeginInfo.renderArea.offset.y = 0
renderPassBeginInfo.renderArea.extent.width = uint32 vk_record.swapchain.current_extent.width
renderPassBeginInfo.renderArea.extent.height = uint32 vk_record.swapchain.current_extent.height
renderPassBeginInfo.clearValueCount = 2
renderPassBeginInfo.pClearValues = addr clearValues[0]
renderPassBeginInfo.render_pass = scene.render_pass
renderPassBeginInfo.framebuffer = vk_record.frame_buffers[vk_record.currentFrameBuffer]
scene[].render_pass_begin_info = renderPassBeginInfo
scene[].scissor = scissor
proc windowResize*( the_waindow: var Waindow
, ../wain/[ window_object
import scene_object
, scene_utils
, scene_record
, main_scenes
, ../vk/[ vulkan
, vkTypes
, vulkan_record
]
, ../drawable/[ shape_object
, text
]
, glm
import ../drawable/text as mText
import ../drawable/shape_object
type
MenuState = enum Begin, Exit
var
ms = MenuState.Begin
#TODO proper dynamic resolution scaling of UI elements
proc load*( rec: var Vulkan_Record
, title: var Scene
, scene_record: var Scene_Record
) =
#[ title.add rec.anSDFText(title, "title", str = "Shapes", size = 18)
title.add rec.anSDFText(title, "begin", str = "begin", size = 14)
title.add rec.anSDFText(title, "exit", str = "exit", size = 14)
title.add rec.a_shape( title.render_pass
, title.current_entity_id
, 4
, "settingsFrame"
, hollow = true
, theSize = 100
)
title.the_text("title").move_to( 150
, 40
)
title.the_text("begin").move_to( 900
, 70
)
title.the_text("exit").move_to( 1600
, 70
)
title.the_text("title").updateFS( outlined = 0.0)
echo rec.swapchain.current_extent.width
title.the_shape("settingsFrame").move_to( rec.swapchain.current_extent.width.float32 / 2
, ((rec.swapchain.current_extent.height.int / 2) + 100 ).float32
)
title.the_shape("settingsFrame").scale( 8
, 4
) ]#
#$title.the_shape("settingsFrame").ubo.model.scale(50)
scene_record.add_scene( addr title
, "title"
)
#TODO: switching states is kinda buggy
proc input*( rec: var Vulkan_Record
, sr: var Scene_Record
) =
case ms
of MenuState.Begin: inc ms
of MenuState.Exit: ms = MenuState.Begin
case ms
of MenuState.Begin: ms = MenuState.Exit
of MenuState.Exit: dec ms
case ms
#of MenuState.Begin: sr.the_main_scene = Main_Scene_Enum.Intro
of MenuState.Exit: quit()
else: discard
proc update*( rec: var Vulkan_Record
, menu: var Scene
) = discard
#[ case ms
of MenuState.Begin:
menu.the_text("begin").updateFS( outlined = 0.1
)
menu.the_text("exit").updateFS( outlined = 0.0)
of MenuState.Exit:
menu.the_text("begin").updateFS( outlined = 0.0)
menu.the_text("exit").updateFS( outlined = 0.1) ]#
proc show*( rec: var Vulkan_Record
, scene: var Scene
) =
var
cmdBufInfo: VkCommandBufferBeginInfo
scissor: VkRect2D
clearValues: array[2,VkClearValue]
renderPassBeginInfo: VkRenderPassBeginInfo
scissor.extent.width = uint32 rec.swapchain.current_extent.width
scissor.extent.height = uint32 rec.swapchain.current_extent.height
scissor.offset.x = 0
scissor.offset.y = 0
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
cmdBufInfo.pNext = nil
clearValues[0].color = VkClearColorValue(float32: [0f, 0f, 0f, 1f])
clearValues[1].depth_stencil = VkClearDepthStencilValue(depth: 1.0f, stencil: 0 )
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
renderPassBeginInfo.pNext = nil
renderPassBeginInfo.renderArea.offset.x = 0
renderPassBeginInfo.renderArea.offset.y = 0
renderPassBeginInfo.renderArea.extent.width = uint32 rec.swapchain.current_extent.width
renderPassBeginInfo.renderArea.extent.height = uint32 rec.swapchain.current_extent.height
renderPassBeginInfo.clearValueCount = 2
renderPassBeginInfo.pClearValues = addr clearValues[0]
renderPassBeginInfo.render_pass = scene.render_pass
renderPassBeginInfo.framebuffer = rec.frame_buffers[rec.currentFrameBuffer]
discard vkBeginCommandBuffer(rec.draw_command_buffers[rec.currentFrameBuffer], addr cmdBufInfo)
vkCmdBeginRenderPass(rec.draw_command_buffers[rec.currentFrameBuffer], addr renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE)
vkCmdSetViewport(rec.draw_command_buffers[rec.currentFrameBuffer], 0, 1, addr rec.current_viewport)
vkCmdSetScissor(rec.draw_command_buffers[rec.currentFrameBuffer], 0, 1, addr scissor)
#[ for shape in scene.shapes.mitems:
rec.buildCommandBuffers shape, scene.render_pass, int rec.currentFrameBuffer
for text in scene.texts.mitems:
mtext.buildCommandBuffers rec, text, scene.render_pass, int rec.currentFrameBuffer ]#
vkCmdEndRenderPass(rec.draw_command_buffers[rec.currentFrameBuffer])
discard vkEndCommandBuffer(rec.draw_command_buffers[rec.currentFrameBuffer])
rec.readyFrame = true
if WAIN_Key.Enter.is_down:
if WAIN_Key.Down.is_down or
WAIN_Key.Left.is_down:
if WAIN_Key.Up.is_down or
WAIN_Key.Right.is_down:
, ../wain/keyboard
import vulkan
, vulkan_record
, pipeline_record
, graphics_pipeline
proc show*( vulkan_record: var Vulkan_Record
, pipeline_record: Pipeline_Record
) =
var
cmdBufInfo = VkCommandBufferBeginInfo(sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO)
scissor: VkRect2D
clearValues: array[2,VkClearValue]
renderPassBeginInfo: VkRenderPassBeginInfo
imageRange = VkImageSubresourceRange( aspectMask: VkImageAspectFlags VK_IMAGE_ASPECT_COLOR_BIT
, levelCount: 1
, layerCount: 1
)
discard vkResetFences( vulkan_record.vk_device
, 1
, addr vulkan_record.fences[vulkan_record.current_frame]
)
if vulkan_record.current_frame_buffer > 1:
vulkan_record.current_frame_buffer = 1
discard vkResetCommandBuffer( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, VkCommandBufferResetFlags 0
)
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: [1f, 0f, 0f, 1f])
clearValues[1].depth_stencil = VkClearDepthStencilValue(depth: 1.0f, stencil: 0 )
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
renderPassBeginInfo.pNext = nil
renderPassBeginInfo.renderArea.offset.x = 0
renderPassBeginInfo.renderArea.offset.y = 0
renderPassBeginInfo.renderArea.extent.width = uint32 vulkan_record.swapchain.current_extent.width
renderPassBeginInfo.renderArea.extent.height = uint32 vulkan_record.swapchain.current_extent.height
renderPassBeginInfo.clearValueCount = 2
renderPassBeginInfo.pClearValues = addr clearValues[0]
renderPassBeginInfo.renderPass = vulkan_record.current_render_pass.vk_handle
renderPassBeginInfo.framebuffer = vulkan_record.frame_buffers[vulkan_record.current_image_index]
discard vkBeginCommandBuffer( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, addr cmdBufInfo
)
vkCmdSetViewport( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, 0
, 1
, addr vulkan_record.current_viewport
)
vkCmdSetScissor( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, 0
, 1
, addr scissor
)
vkCmdClearColorImage( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, vulkan_record.swapchain.images[vulkan_record.current_frame_buffer]
, VK_IMAGE_LAYOUT_GENERAL
, addr clearValues[0].color
, 1
, addr imageRange
)
vkCmdBeginRenderPass( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, addr renderPassBeginInfo
, VK_SUBPASS_CONTENTS_INLINE
)
var
offsets = VkDeviceSize 0
#[ vkCmdBindDescriptorSets( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, VK_PIPELINE_BIND_POINT_GRAPHICS
, pipeline_record.pipelines["test"].pipeline_layout
, 0
, 1
, addr descriptor_set
, 0, nil
)
]#
vkCmdEndRenderPass vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
discard vkEndCommandBuffer vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
vulkan_record.ready_frame = true
proc submit_frame*( image_index: var uint32
, render_complete_semaphore: VkSemaphore
, queue: VkQueue
, current_swapchain_handle: VkSwapchainKHR
) =
var
presentInfo: VkPresentInfoKHR
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR
presentInfo.pNext = nil
presentInfo.waitSemaphoreCount = 1
presentInfo.pWaitSemaphores = addr render_complete_semaphore
presentInfo.swapchainCount = 1
presentInfo.pSwapchains = addr current_swapchain_handle
present_info.pImageIndices = addr image_index
# Check if a wait semaphore has been specified to wait for
# before presenting the image
if (render_complete_semaphore.int != 0):
presentInfo.pWaitSemaphores = addr render_complete_semaphore
presentInfo.waitSemaphoreCount = 1
#TODO: WHY DOES THIS MEMORY LEAK EVERY FRAME
var preres = vkQueuePresentKHR( queue
, addr presentInfo
)
#if preres == VK_SUBOPTIMAL_KHR: quit "bad vkQueuePresentKHR"
# vulkan_record.windowResize scene
# scene.rebuild vulkan_record
# discard vkDeviceWaitIdle vulkan_record.vk_device
# vulkan_record.ready_frame = true
proc send_frame*( vulkan_record: var Vulkan_Record
) =
#prep frame
discard vkWaitForFences( vulkan_record.vk_device
, 1
, addr vulkan_record.fences[vulkan_record.current_frame]
, VKBool32 true
, uint64.high
)
var
res = vkAcquireNextImageKHR( vulkan_record.vk_device
, vulkan_record.swap_chain.handle
, uint64.high
, vulkan_record.present_semaphores[vulkan_record.current_frame]
, VkFence 0
, addr vulkan_record.current_image_index
)
if res == VK_ERROR_OUT_OF_DATE_KHR: discard
#resize_screen()
# show l#
discard vkResetFences( vulkan_record.vk_device
, 1
, addr vulkan_record.fences[vulkan_record.current_frame]
)
discard vkResetCommandBuffer( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, VkCommandBufferResetFlags 0
)
var
cmdBufInfo = VkCommandBufferBeginInfo(sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO)
scissor: VkRect2D
clearValues: array[2,VkClearValue]
renderPassBeginInfo: VkRenderPassBeginInfo
imageRange = VkImageSubresourceRange( aspectMask: VkImageAspectFlags VK_IMAGE_ASPECT_COLOR_BIT
, levelCount: 1
, layerCount: 1
)
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: [1f, 0f, 0f, 1f])
clearValues[1].depth_stencil = VkClearDepthStencilValue(depth: 1.0f, stencil: 0 )
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
renderPassBeginInfo.pNext = nil
renderPassBeginInfo.renderArea.offset.x = 0
renderPassBeginInfo.renderArea.offset.y = 0
renderPassBeginInfo.renderArea.extent.width = uint32 vulkan_record.swapchain.current_extent.width
renderPassBeginInfo.renderArea.extent.height = uint32 vulkan_record.swapchain.current_extent.height
renderPassBeginInfo.clearValueCount = 2
renderPassBeginInfo.pClearValues = addr clearValues[0]
renderPassBeginInfo.renderPass = vulkan_record.current_render_pass.vk_handle
renderPassBeginInfo.framebuffer = vulkan_record.frame_buffers[vulkan_record.current_image_index]
discard vkBeginCommandBuffer( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, addr cmdBufInfo
)
vkCmdBeginRenderPass( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, addr renderPassBeginInfo
, VK_SUBPASS_CONTENTS_INLINE
)
vkCmdSetViewport( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, 0
, 1
, addr vulkan_record.current_viewport
)
vkCmdSetScissor( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, 0
, 1
, addr scissor
)
vkCmdBindDescriptorSets( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, VK_PIPELINE_BIND_POINT_GRAPHICS
, vulkan_record.current_graphics_pipeline.pipelineLayout
, 0
, 1
, addr vulkan_record.uniform_buffers[vulkan_record.current_frame_buffer].descriptor_set
, 0
, nil
)
# Bind the rendering pipeline
# The pipeline (state object) contains all states of the rendering pipeline, binding it will set all the states specified at pipeline creation time
vkCmdBindPipeline( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, VK_PIPELINE_BIND_POINT_GRAPHICS
, vulkan_record.current_graphics_pipeline.pipeline
)
# Bind triangle vertex buffer (contains position and colors)
var offsets: array[1, VkDeviceSize] = [VkDeviceSize 0]
#[ vkCmdBindVertexBuffers(vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, 0
, 1
, &vertices.buffer
, offsets
)
# Bind triangle index buffer
vkCmdBindIndexBuffer( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, indices.buffer
, 0
, VK_INDEX_TYPE_UINT32
)
# Draw indexed triangle
vkCmdDrawIndexed( vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, indices.count
, 1
, 0
, 0
, 1
) ]#
vkCmdEndRenderPass vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
discard vkEndCommandBuffer vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
# show l#
var
waitStageMask = VkPipelineStageFlags VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
submitInfo = VkSubmitInfo( sType: VK_STRUCTURE_TYPE_SUBMIT_INFO
, pWaitDstStageMask: addr waitStageMask
, pWaitSemaphores: addr vulkan_record.present_semaphores[vulkan_record.current_frame]
, waitSemaphoreCount: 1
, pSignalSemaphores: addr vulkan_record.render_semaphores[vulkan_record.current_frame]
, commandBufferCount: 1
, pCommandBuffers: addr vulkan_record.draw_command_buffers[vulkan_record.current_frame_buffer]
, signalSemaphoreCount: 1
)
discard vkQueueSubmit( vulkan_record.queue
, 1
, submitInfo.addr
, vulkan_record.fences[vulkan_record.current_frame]
)
if vulkan_record.current_frame == 2:
vulkan_record.current_frame = 1
submit_frame( vulkan_record.current_image_index
, vulkan_record.render_semaphores[vulkan_record.current_frame]
, vulkan_record.queue
, vulkan_record.swapchain.handle
)
#[
static i32 find_memory_index(vulkan_context *context
, u32 type_filter
, u32 property_flags)
{
for (u32 i = 0; i < memory_properties.memoryTypeCount; ++i) {
// Check each memory type to see if its bit is set to 1.
if ( type_filter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & property_flags) ==
property_flags
) {
return i;
}
}
let
memory_type_bits = 1 shl memory_index
is_required_memory_type = (the_type_bits and memory_type_bits.uint32)
property_flags: VkMemoryPropertyFlags = memory_properties.memoryTypes[memory_index].propertyFlags
memory_has_required_properties = ( property_flags.int and
required_memory_properties.int
)
var
is_required_memory_property = bitand( the_type_bits_filter.int
, (1 shl memory_index)
) >= 1
the_memory_indexs_property_flag = memory_properties.memoryTypes[memory_index].propertyFlags.int
# is == 1 correct?
if is_required_memory_type == 1 and
memory_has_required_properties == 1:
return memory_index
quit("no matching memory type could be found:")
#echo "RMP: ", is_required_memory_property, " <> (", bitand( the_type_bits_filter.int, (1 shl memory_index)), ") ", the_memory_indexs_property_flag
if is_required_memory_property and
bitand( the_memory_indexs_property_flag
, required_memory_properties.int
) == required_memory_properties.int:
return memory_index
quit("find_memory_with_property: no matching memory type could be found:")
import vulkan
, vulkan_record
, pipeline_record
, ../scene/[ scene_record
, scene_controller
]
proc prepare_frame*(rec: var Vulkan_Record
, scene_record: var Scene_Record
, pipeline_record: Pipeline_Record
) =
discard vkAcquireNextImageKHR( rec.vk_device
, rec.swapChain.handle
, uint64.high
, rec.presentCompleteSemaphore
, VkFence 0
, addr rec.currentFrameBuffer
)
discard vkWaitForFences(rec.vk_device, 1, addr rec.fences[rec.currentFrameBuffer], VKBool32 true, uint64.high)
discard vkResetFences(rec.vk_device, 1, addr rec.fences[rec.currentFrameBuffer])
#
proc submit_frame*( current_frame_buffer: uint32
, render_complete_semaphore: VkSemaphore
, queue: VkQueue
#, scene: var Scene
, present_info: var VkPresentInfoKHR
) =
#for shape in scene.shapes.mitems:
#if shape.changed: rec.vk_device.updateCamera shape
#[ for text in scene.texts.mitems:
if text.changed:
text.updateCamera ]#
# THE M A G I C (presenting) queuePresent
#[ var presentInfo: VkPresentInfoKHR
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR
presentInfo.pNext = nil
presentInfo.swapchainCount = 1
presentInfo.pSwapchains = addr rec.swapChain.swapChainKHR ]#
present_info.pImageIndices = addr current_frame_buffer #rec.currentFrameBuffer
# Check if a wait semaphore has been specified to wait for
# before presenting the image
if (render_complete_semaphore.int != 0):
presentInfo.pWaitSemaphores = addr render_complete_semaphore
presentInfo.waitSemaphoreCount = 1
#TODO: WHY DOES THIS MEMORY LEAK EVERY FRAME
var preres = vkQueuePresentKHR( queue
, addr presentInfo
)
#if preres == VK_SUBOPTIMAL_KHR: quit "bad vkQueuePresentKHR"
# rec.windowResize scene
# scene.rebuild rec
# discard vkDeviceWaitIdle rec.vk_device
# rec.readyFrame = true
proc draw*(rec: var Vulkan_Record
, scene_record: var Scene_Record
, pipeline_record: Pipeline_Record
) =
if rec.readyFrame:
rec.prepare_frame scene_record, pipeline_record
scene_record.draw_current_scene rec, pipeline_record
var
waitStageMask = VkPipelineStageFlags VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
submitInfo = VkSubmitInfo( sType: VK_STRUCTURE_TYPE_SUBMIT_INFO
, pWaitDstStageMask: addr waitStageMask
, pWaitSemaphores: addr rec.presentCompleteSemaphore
, waitSemaphoreCount: 1
, pSignalSemaphores: addr rec.renderCompleteSemaphore
, commandBufferCount: 1
, pCommandBuffers: addr rec.draw_command_buffers[rec.currentFrameBuffer]
, signalSemaphoreCount: 1
)
discard vkQueueSubmit( rec.queue
, 1
, submitInfo.addr
, rec.fences[rec.currentFrameBuffer]
)
submit_frame( rec.currentFrameBuffer
, rec.renderCompleteSemaphore
, rec.queue
, scene_record.current_scene[].present_info
)
#rec.readyFrame = false
vkCreateBuffer = cast[ proc( device: VkDevice
, pCreateInfo: ptr VkBufferCreateInfo
, pAllocator: ptr VkAllocationCallbacks
, pBuffer: ptr VkBuffer
): VkResult {.stdcall.}
] (vkGetDeviceProcAddr( device
, "vkCreateBuffer"
) )
vkGetBufferMemoryRequirements =cast[ proc(device: VkDevice
, buffer: VkBuffer
, pMemoryRequirements: ptr VkMemoryRequirements
): void {.stdcall.}]
((vkGetDeviceProcAddr( device
, "vkGetBufferMemoryRequirements"
) ))
vkBindBufferMemory = cast[proc(device: VkDevice, buffer: VkBuffer, memory: VkDeviceMemory, memoryOffset: VkDeviceSize): VkResult {.stdcall.}]
(vkGetDeviceProcAddr( device
, "vkBindBufferMemory"
))
result.master_vertex_buffer = a_vulkan_buffer( result.vk_device
, result.gpu.memory_properties
, VkBufferUsageFlags bitor( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT.ord
, VK_BUFFER_USAGE_TRANSFER_DST_BIT.ord
)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
, MiB_vkds(256)
)
result.master_index_buffer = a_vulkan_buffer( result.vk_device
, result.gpu.memory_properties
, VkBufferUsageFlags bitor( VK_BUFFER_USAGE_INDEX_BUFFER_BIT.ord
, VK_BUFFER_USAGE_TRANSFER_DST_BIT.ord
)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
, MiB_vkds(128)
)
result.master_uniform_buffer = a_vulkan_buffer( result.vk_device
, result.gpu.memory_properties
, VkBufferUsageFlags VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
, VkMemoryPropertyFlags ( VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT.ord or
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT.ord
)
, MiB_vkds(256)
)
#[ result.master_vertex_buffer = a_vulkan_buffer( result.vk_device
, result.gpu.memory_properties
, VkBufferUsageFlags bitor( VK_BUFFER_USAGE_VERTEX_BUFFER_BIT.ord
, VK_BUFFER_USAGE_TRANSFER_DST_BIT.ord
)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
, MiB_vkds(256)
) ]#
#[ master_index_buffer = a_vulkan_buffer(
)
master_uniform_buffer = a_vulkan_buffer(
)
]#
, addr vulkan_record.master_vertex_buffer.data[vulkan_record.master_vertex_buffer.current_data_offset]
, Natural vertex_data.sizeof
)
, addr vulkan_record.master_vertex_buffer.data[vulkan_record.master_vertex_buffer.current_data_offset]
, Natural vertex_data.sizeof
)
, addr vulkan_record.master_index_buffer.data[vulkan_record.master_index_buffer.current_data_offset]
, Natural index_data.sizeof
)
, addr vulkan_record.master_index_buffer.data[vulkan_record.master_index_buffer.current_data_offset]
, Natural index_data.sizeof
)
, gpu_memory_properties: VkPhysicalDeviceMemoryProperties
, allocation_size: VkDeviceSize
, buffer_usage_flags: VkBufferUsageFlags
, memory_flags: VkMemoryPropertyFlags
): Buffer =
, gpu_memory_properties: VkPhysicalDeviceMemoryProperties
, buffer_usage_flags: VkBufferUsageFlags
, memory_flags: VkMemoryPropertyFlags
, allocation_size: VkDeviceSize
): Buffer =
allocation_info.memoryTypeIndex = gpu_memory_properties.find_memory_with_property( mem_reqs.memoryTypeBits
, memory_flags
)
allocation_info.memoryTypeIndex =
gpu_memory_properties.find_memory_with_property( mem_reqs.memoryTypeBits
, memory_flags
)
, result.device_memory
, VkDeviceSize 0
, allocation_size
, VkMemoryMapFlags 0
, cast[ptr pointer] (result.data)
) == VK_SUCCESS
, result.device_memory
, VkDeviceSize 0
, allocation_size
, VkMemoryMapFlags 0
, cast[ptr pointer] (result.data)
) == VK_SUCCESS
import ../scene/[scene_object
, scene_utils
, scene_record
, main_scenes
]
, ../vk/[ vulkan
, vkTypes
, vulkan_record
]
, ../drawable/[ shape_object
, text
]
, ../wain/keyboard
, glm
import ../drawable/text as mText
import ../drawable/shape_object
type
MenuState = enum Begin, Exit
var
ms = MenuState.Begin
#TODO proper dynamic resolution scaling of UI elements
proc load*( rec: var Vulkan_Record
, title: var Scene
, scene_record: var Scene_Record
) =
#[ title.add rec.anSDFText(title, "title", str = "Shapes", size = 18)
title.add rec.anSDFText(title, "begin", str = "begin", size = 14)
title.add rec.anSDFText(title, "exit", str = "exit", size = 14)
title.add rec.a_shape( title.render_pass
, title.current_entity_id
, 4
, "settingsFrame"
, hollow = true
, theSize = 100
)
title.the_text("title").move_to( 150
, 40
)
title.the_text("begin").move_to( 900
, 70
)
title.the_text("exit").move_to( 1600
, 70
)
title.the_text("title").updateFS( outlined = 0.0)
echo rec.swapchain.current_extent.width
title.the_shape("settingsFrame").move_to( rec.swapchain.current_extent.width.float32 / 2
, ((rec.swapchain.current_extent.height.int / 2) + 100 ).float32
)
title.the_shape("settingsFrame").scale( 8
, 4
) ]#
#$title.the_shape("settingsFrame").ubo.model.scale(50)
scene_record.add_scene( addr title
, "title"
)
#TODO: switching states is kinda buggy
proc input*( rec: var Vulkan_Record
, sr: var Scene_Record
) =
if WAIN_Key.Up.is_down or
WAIN_Key.Right.is_down:
case ms
of MenuState.Begin: inc ms
of MenuState.Exit: ms = MenuState.Begin
if WAIN_Key.Down.is_down or
WAIN_Key.Left.is_down:
case ms
of MenuState.Begin: ms = MenuState.Exit
of MenuState.Exit: dec ms
if WAIN_Key.Enter.is_down:
case ms
#of MenuState.Begin: sr.the_main_scene = Main_Scene_Enum.Intro
of MenuState.Exit: quit()
else: discard
proc update*( rec: var Vulkan_Record
, menu: var Scene
) = discard
#[ case ms
of MenuState.Begin:
menu.the_text("begin").updateFS( outlined = 0.1
)
menu.the_text("exit").updateFS( outlined = 0.0)
of MenuState.Exit:
menu.the_text("begin").updateFS( outlined = 0.0)
menu.the_text("exit").updateFS( outlined = 0.1) ]#
proc build_scene*( rec: var Vulkan_Record
, scene: var Scene
) =
var
cmdBufInfo: VkCommandBufferBeginInfo
scissor: VkRect2D
clearValues: array[2,VkClearValue]
renderPassBeginInfo: VkRenderPassBeginInfo
scissor.extent.width = uint32 rec.swapchain.current_extent.width
scissor.extent.height = uint32 rec.swapchain.current_extent.height
scissor.offset.x = 0
scissor.offset.y = 0
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
cmdBufInfo.pNext = nil
clearValues[0].color = VkClearColorValue(float32: [0f, 0f, 0f, 1f])
clearValues[1].depth_stencil = VkClearDepthStencilValue(depth: 1.0f, stencil: 0 )
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
renderPassBeginInfo.pNext = nil
renderPassBeginInfo.renderArea.offset.x = 0
renderPassBeginInfo.renderArea.offset.y = 0
renderPassBeginInfo.renderArea.extent.width = uint32 rec.swapchain.current_extent.width
renderPassBeginInfo.renderArea.extent.height = uint32 rec.swapchain.current_extent.height
renderPassBeginInfo.clearValueCount = 2
renderPassBeginInfo.pClearValues = addr clearValues[0]
#renderPassBeginInfo.render_pass = scene.render_pass
renderPassBeginInfo.framebuffer = rec.frame_buffers[rec.currentFrameBuffer]
discard vkBeginCommandBuffer(rec.draw_command_buffers[rec.currentFrameBuffer], addr cmdBufInfo)
vkCmdBeginRenderPass(rec.draw_command_buffers[rec.currentFrameBuffer], addr renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE)
vkCmdSetViewport(rec.draw_command_buffers[rec.currentFrameBuffer], 0, 1, addr rec.current_viewport)
vkCmdSetScissor(rec.draw_command_buffers[rec.currentFrameBuffer], 0, 1, addr scissor)
#[ for shape in scene.shapes.mitems:
rec.buildCommandBuffers shape, scene.render_pass, int rec.currentFrameBuffer
for text in scene.texts.mitems:
mtext.buildCommandBuffers rec, text, scene.render_pass, int rec.currentFrameBuffer ]#
vkCmdEndRenderPass(rec.draw_command_buffers[rec.currentFrameBuffer])
discard vkEndCommandBuffer(rec.draw_command_buffers[rec.currentFrameBuffer])
rec.readyFrame = true
import ../scene/[ scene_object
, scene_record
, scene_utils
]
, ../vk/[ vulkan_record
, pipeline_record
]
, ../drawable/[ colors
, actions
, grid
, plane
, shape_object
, shape_primitives
, shape_types
, text
, text_types
]
, vmath
proc load*( scene_record: var Scene_Record
, vulkan_record: var Vulkan_Record
) =
var
test_area = a_scene(vulkan_record)
test_area.add( a_shape( vulkan_record
, test_area.current_entity_id
, 3
, "tri"
, vec2(100.0,100.0)
) )
proc input*( scene_record: var Scene_Record
, vulkan_record: var Vulkan_Record
) = discard
proc update*( scene_record: var Scene_Record
, vulkan_record: var Vulkan_Record
, fps: string
) = discard
proc build_scene*( scene_record: var Scene_Record
, vulkan_record: var Vulkan_Record
, pipeline_record: Pipeline_Record
) = discard
{.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
{.experimental: "codeReordering".}
{.deadCodeElim: on.}
#TODO: REBUILD render_Pass_begin_info on window size change
import ../vk/[ vulkan_record
, vulkan_utils
, vulkan
, depth_stencil
, swapchain
, buffer
]
, scene_object
, scene_record
, ../deshn_entity/[ being
]
, ../drawable/[ shape_object
, text_types
, plane
]
, ../wain/[ waindow_object
]
, std/[ tables
, bitops
]
, glm
proc a_scene*( vk_record: var Vulkan_Record
): Scene =
result = Scene()
result.entities = newTable[string, int]()
proc theIds*(scene: Scene): seq[int] =
for t in scene.shapes: result.add t.id
proc theNames*(scene: Scene): seq[string] =
for t in scene.shapes: result.add t.name
proc the_shape*( scene: var Scene
, id: int
, name: string
): var Shape =
for t in scene.shapes.mitems:
if t.id == id: return t
quit("ERROR: Entity[SHAPE] not found: " & name & ": id" & $id)
proc the_shape*( scene: var Scene
, name: string
): var Shape =
scene.the_shape scene.entities[name], name
proc the_deshn_being*( scene: var Scene
, id: int
, name: string
): var Deshn_Being =
for t in scene.deshn_beings.mitems:
if t.id == id: return t
quit("ERROR: Entity[SHAPE] not found: " & name & ": id" & $id)
proc the_deshn_being*( scene: var Scene
, name: string
): var Deshn_Being =
scene.the_deshn_being scene.entities[name], name
#[ proc the_text*( scene: Scene
, id: int
, name: string
): var SDFText =
#WARNING]: Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]
for t in scene.texts.mitems:
if t.id == id: return t
quit("ERROR: Entity[SDFTEXT] not found: " & name & " / id:" & $id)
proc the_text*( scene: Scene
, name: string
): var SDFText = scene.the_text scene.entities[name], name ]#
# # TODO: need drawable-independent command buffers
# proc build*( vk_record: Vulkan_Record
# , scene: var Scene
# ) =
proc the_plane*( scene: var Scene
, id: int
, name: string
): var Plane =
for t in scene.planes.mitems:
if t.id == id: return t
quit("ERROR: Entity[SHAPE] not found: " & name & ": id" & $id)
proc the_plane*( scene: var Scene
, name: string
): var Plane =
scene.the_plane scene.entities[name], name
proc add*( scene: var Scene
, shape: Shape
) =
#echo "adding: ", sh.name, " ", sh.id
scene.shapes.add shape
scene.entities[shape.name] = shape.id
scene.current_entity_id += 1
scene.the_vertices.add shape.vertices
scene.the_indices.add shape.indices
#[ proc add*( scene: var Scene
, text: SDFText
) =
scene.texts.add text
scene.entities[text.name] = scene.current_entity_id
scene.current_entity_id += 1
for text_vert in text.vertices:
scene.the_vertices.add text_vert.pos.x
scene.the_vertices.add text_vert.pos.y
scene.the_vertices.add text_vert.pos.z
scene.the_vertices.add text_vert.uv.x
scene.the_vertices.add text_vert.uv.y
scene.the_indices.add text.indices
]#
proc add*( scene: var Scene
, deshn_being: Deshn_Being
) =
#echo "adding: ", sh.name, " ", sh.id
scene.deshn_beings.add deshn_being
scene.entities[deshn_being.name] = deshn_being.id
scene.current_entity_id += 1
scene.add deshn_being.shape
proc add*( scene: var Scene
, plane: Plane
) =
#echo "adding: ", sh.name, " ", sh.id
scene.planes.add plane
scene.entities[plane.name] = plane.id
scene.current_entity_id += 1
scene.add plane.shape
proc prepare_vertices*( scene: var Scene
, vk_device: VkDevice
, memory_properties: VkPhysicalDeviceMemoryProperties
, command_pool: VkCommandPool
, queue: VkQueue
, master_vertex_buffer: var Buffer
, master_index_buffer: var Buffer
) =
var
copyCmd: VkCommandBuffer = vk_device.getCommandBuffers(command_pool, true)
copyRegion: VkBufferCopy
data: pointer
#[ copyMem( data, addr scene.the_vertices[0]
, Natural scene.the_vertices.sizeof
)
vkUnmapMemory( vk_device
, scene.staging_vertex_buffer.device_memory
)
discard vkBindBufferMemory( vk_device
, scene.staging_vertex_buffer.vkbuffer
, scene.staging_vertex_buffer.device_memory
, VkDeviceSize 0
)
discard vkBindBufferMemory( vk_device
, scene.vertex_buffer.vkbuffer
, scene.vertex_buffer.device_memory
, VkDeviceSize 0
)
scene.staging_index_buffer = a_vulkan_buffer( vk_device
, memory_properties
, VkBufferUsageFlags VK_BUFFER_USAGE_TRANSFER_SRC_BIT
, VkMemoryPropertyFlags bitor( VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT.ord
, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT.ord
)
, VkDeviceSize scene.the_indices.sizeof
)
scene.index_buffer = a_vulkan_buffer( vk_device
, memory_properties
, VkBufferUsageFlags bitor(VK_BUFFER_USAGE_INDEX_BUFFER_BIT.ord, VK_BUFFER_USAGE_TRANSFER_DST_BIT.ord)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
, VkDeviceSize scene.the_indices.sizeof
)
vk_device.map_memory( scene.staging_index_buffer.device_memory
, data
)
copyMem(data, addr scene.the_indices[0], Natural scene.the_indices.sizeof)
vkUnmapMemory(vk_device, scene.staging_index_buffer.device_memory)
discard vkBindBufferMemory(vk_device, scene.staging_index_buffer.vkbuffer, scene.staging_index_buffer.device_memory, VkDeviceSize 0)
discard vkBindBufferMemory(vk_device, scene.index_buffer.vkbuffer, scene.index_buffer.device_memory, VkDeviceSize 0)
copyRegion.size = VkDeviceSize scene.the_vertices.sizeof
vkCmdCopyBuffer(copyCmd, scene.staging_vertex_buffer.vkbuffer, scene.vertex_buffer.vkbuffer, 1.uint32, addr copyRegion)
copyRegion.size = VkDeviceSize scene.the_indices.sizeof
vkCmdCopyBuffer(copyCmd, scene.staging_index_buffer.vkbuffer, scene.index_buffer.vkbuffer, 1.uint32, addr copyRegion)
# # Flushing the command buffer will also submit it to the queue and
# # uses a fence to ensure that all commands have been executed before returning
vk_device.flushCommandBuffer queue, command_pool, copyCmd
# Destroy staging buffers
# Note: Staging buffer must not be deleted before the copies have been submitted and executed
vkDestroyBuffer( vk_device
, scene.staging_vertex_buffer.vkbuffer
, nil
)
vkFreeMemory( vk_device
, scene.staging_vertex_buffer.device_memory
, nil
)
vkDestroyBuffer( vk_device
, scene.staging_index_buffer.vkbuffer
, nil
)
vkFreeMemory( vk_device
, scene.staging_index_buffer.device_memory
, nil
) ]#
proc clean_up*( vk_record: var Vulkan_Record
, scene: var Scene
) =
discard vkDeviceWaitIdle vk_record.vk_device
# recycle the Pools!
# vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL)
# vkDestroyCommandPool(demo->device, demo->command_pool, NULL);
#should we have an initial "setup command buffer"?
#[ for shape in scene.shapes:
vk_record.vk_device.vkDestroyPipeline(shape.graphicsPipeline.pipeline, nil)
vk_record.vk_device.vkDestroyPipelineLayout(shape.graphicsPipeline.pipelineLayout, nil)
vk_record.vk_device.vkDestroyDescriptorSetLayout(shape.descrSetLayout, nil)
for text in scene.texts:
vk_record.vk_device.vkDestroyPipeline(text.graphicsPipeline.pipeline, nil)
vk_record.vk_device.vkDestroyPipelineLayout(text.graphicsPipeline.pipelineLayout, nil)
vk_record.vk_device.vkDestroyDescriptorSetLayout(text.descrSetLayout, nil) ]#
#[ for i,fb in vk_record.draw_command_buffers:
vkFreeCommandBuffers( vk_record.vk_device
, vk_record.command_pool
, 1
, addr vk_record.draw_command_buffers[i]
)
vk_record.vk_device.vkDestroyRenderPass(scene.render_pass, nil) ]#
#[
proc rebuild_render_pass_info*( vk_record: var Vulkan_Record
, scene: var Scene
) =
var
scissor = VkRect2D( extent: VkExtent2D( width: uint32 vk_record.swapchain.current_extent.width
, height: uint32 vk_record.swapchain.current_extent.height
)
, offset: VkOffset2D( x: 0
, y: 0
)
)
renderPassBeginInfo = VkRenderPassBeginInfo(sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO)
clearValues: array[2,VkClearValue]
clearValues[0].color = VkClearColorValue(float32: [0f, 0f, 0f, 1f])
clearValues[1].depth_stencil = VkClearDepthStencilValue( depth: 1.0f
, stencil: 0
)
renderPassBeginInfo.pNext = nil
renderPassBeginInfo.renderArea.offset.x = 0
renderPassBeginInfo.renderArea.offset.y = 0
renderPassBeginInfo.renderArea.extent.width = uint32 vk_record.swapchain.current_extent.width
renderPassBeginInfo.renderArea.extent.height = uint32 vk_record.swapchain.current_extent.height
renderPassBeginInfo.clearValueCount = 2
renderPassBeginInfo.pClearValues = addr clearValues[0]
renderPassBeginInfo.render_pass = scene.render_pass
renderPassBeginInfo.framebuffer = vk_record.frame_buffers[vk_record.currentFrameBuffer]
scene[].render_pass_begin_info = renderPassBeginInfo
scene[].scissor = scissor ]#
import scene_object
, main_scenes
, ../vk/vulkan_record
import std/tables
type
Scene_Record_Object = object of RootObj
current_scene*: ptr Scene
main_scene_table*: Table[string, ptr Scene]
current_scene_name*: Main_Scenes
Scene_Record* = ref object of Scene_Record_Object
proc a_scene_record*( the_main_scene: Main_Scenes
, current_scene: ptr Scene = nil
): Scene_Record =
result = Scene_Record( current_scene: current_scene
, main_scene_table: initTable[string, ptr Scene]()
)
proc add_scene*( scene_record: var Scene_Record
, scene: ptr Scene
, scene_name: string
) =
scene_record.main_scene_table[scene_name] = scene
proc get_scene*( scene_record: var Scene_Record
, scene_name: string
): ptr Scene =
scene_record.main_scene_table[scene_name]
import tables
, ../drawable/[ shape_object
, text_types
, plane
]
, ../deshn_entity/[ being
]
, ../vk/[ vulkan
, vkTypes
, depth_stencil
, buffer
]
type
Scene_Object = object of RootObj
device*: ptr VkDevice
entities*: TableRef[string, int]
shapes*: seq[Shape]
#texts*: seq[SDFText]
planes*: seq[Plane]
deshn_beings*: seq[Deshn_Being]
current_entity_id*: int
vertex_buffer*: Buffer
index_buffer*: Buffer
staging_vertex_buffer*: Buffer
staging_index_buffer*: Buffer
#render_pass_begin_info*: VkRenderPassBeginInfo
#scissor*: VkRect2D
#render_pass*: VkRenderPass
#depth_stencil*: Depth_Stencil
present_info*: VkPresentInfoKHR
# TODO: a better way , instead of having to redundantly copy vertices and indices
the_vertices*: seq[float32]
the_indices*: seq[uint32]
indirect_commands*: seq[VkDrawIndexedIndirectCommand]
Scene* = ref object of Scene_Object
import ../the_scenes/[ intro
, title
, test_area
]
, main_scenes
, scene_object
, scene_record
import ../vk/[ vulkan_record
, pipeline_record
]
proc load*( scene_record: var Scene_Record
, vulkan_record: var Vulkan_Record
) =
case scene_record.current_scene_name
of Title: discard
of Intro: discard
of Test_Area: test_area.load( scene_record
, vulkan_record
)
proc input*( scene_record: var Scene_Record
, vulkan_record: var Vulkan_Record
) =
case scene_record.current_scene_name
of Title: discard
of Intro: discard
of Test_Area: test_area.input( scene_record
, vulkan_record
)
proc update*( scene_record: var Scene_Record
, vulkan_record: var Vulkan_Record
, fps: string
) =
case scene_record.current_scene_name
of Title: discard
of Intro: discard
of Test_Area: test_area.update( scene_record
, vulkan_record
, fps
)
proc draw_current_scene*( scene_record: var Scene_Record
, vulkan_record: var Vulkan_Record
, pipeline_record: Pipeline_Record
) =
case scene_record.current_scene_name
of Title: discard
of Intro: discard
of Test_Area: test_area.build_scene( scene_record
, vulkan_record
, pipeline_record
)
type
Main_Scenes* = enum
Title = 0 ,
Intro = 1 ,
Test_Area = 99
#[ {.experimental: "codeReordering".}
{.deadCodeElim: on.}
import glm
, ../camera
, tables
, freetype/[ freetype
, fttypes
]
, ../vk/[ vulkan
, buffer
, vulkan_utils
, vkTypes
, vulkan_record
, graphics_pipeline
]
, bitops
, ../drawable/texture
, ../utils/lets
type
# Area = ref object
# x: int
# y: int
# width: int
# height: int
Bmchar* = object
x*: uint32
y*: uint32
width*: uint32
height*: uint32
xoffset*: int32
yoffset*: int32
xadvance*: int32
page*: uint32
#chl ??
TextVert* = object
pos*: Vec3[float32]
uv*: Vec2[float32]
#color*: Vec4[float]
#texCoord*: Vec2[float]
#blendMode*: int32
#data*: array[4, int32]
TextUboFS* = ref object
outlineColor*: Vec4[float32]
outlineWidth*: float
outline*: bool
TextPipelines* = ref object
sdf*: VkPipeline
bitmap*: VkPipeline
Glyph* = object
top*: int
left*: int
width*: int
height*: int
adv*: int
texture*: Texture2d
face*: FT_Face
ind*: FT_Uint
PBMFont* = object
chars*: array[255,Bmchar]
face*: FT_Face
glyphs*: Table[uint16, Glyph]
VertDescr* = ref object of VertDescrObj
VertDescrObj* = object of RootObj
inputState*: VkPipelineVertexInputStateCreateInfo
bindingDescriptions*: seq[VkVertexInputBindingDescription]
attributeDescriptions*: seq[VkVertexInputAttributeDescription]
UBOVS* = object
proj*: Mat4[float32]
model*: Mat4[float32]
view*: Mat4[float32] # ?
UBOFS* = object
outlineColor*: Vec4[float32]
outlineWidth*: float32
outlined*: float32
UBOS* = ref object of UBOSObj
UBOSObj* = object of RootObj
vs*: UBOVS
fs*: UBOFS
SDFTextObj = object of RootObj
camera*: Camera
descrSet*: VkDescriptorSet
descrSetLayout*: VkDescriptorSetLayout
id*: int
indices*: seq[uint32]
indexCount*: uint32
indexedAmount*: uint32
indexBuffer*: Buffer
vertexBuffer*: Buffer
uniBufferV*: Buffer
uniBufferF*: Buffer
font*: PBMFont
name*: string
pipelineCache*: VkPipelineCache
graphicsPipeline*: Graphics_Pipeline
stVertexBuffer*: Buffer
stIndexBuffer*: Buffer
texture*: Texture2D
ubos*: UBOs
descrPool*: VkDescriptorPool
changed*: bool
strChanged*: bool
str*: string
camera_type*: Camera_Kind
device*: ptr VkDevice
size*: float32
vertices*: seq[TextVert]
theVkRec*: ptr Vulkan_Record
SDFText* = ref object of SDFTextObj
TextureWindow* = object
x0*: float
y0*: float
x1*: float
y1*: float
TextureAtlas* = ref object of TextureAtlasObj
TextureAtlasObj = object of RootObj
width*: uint32
height*: uint32
sampler*: VkSampler
descPool*: VkDescriptorPool
descrSet*: VkDescriptorSet
descrSetLayout*: VkDescriptorSetLayout
imageView*: VkImageView
boundImage*: BoundImage
glyphs*: Table[uint16, Glyph]
proc aGlyph*(font: PBMFont, glyphs: var Table[uint16, Glyph], key: uint16): Glyph =
if glyphs.hasKey(key): return glyphs[key]
else:
var
gind = FT_Get_Char_Index(font.face, key)
#auto glyph = std::make_shared<Glyph>(m_face, glyphIndex, m_textureAtlas);
g = Glyph(face: font.face, ind: gind)
glyphs[key] = g
return g
proc transitionImageLayout( rec: var Vulkan_Record
, image: VkImage
, oldLayout: VkImageLayout
, newLayout: VkImageLayout) =
var
sourceStage: VkPipelineStageFlags = VkPipelineStageFlags VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
destinationStage: VkPipelineStageFlags = VkPipelineStageFlags VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
cmdBuffer: VkCommandBuffer = beginSingleTimeCommands( rec.vk_device
, rec.command_pool
)
barrier = VkImageMemoryBarrier( sType: VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
, oldLayout: oldLayout
, newLayout: newLayout
, srcQueueFamilyIndex: VK_QUEUE_FAMILY_IGNORED
, dstQueueFamilyIndex: VK_QUEUE_FAMILY_IGNORED
, image: image
, subresourceRange: VkImageSubresourceRange( aspectMask: VkImageAspectFlags VK_IMAGE_ASPECT_COLOR_BIT
, baseMipLevel: 0
, levelCount: 1
, baseArrayLayer: 0
, layerCount: 1
)
)
case oldLayout:
of VK_IMAGE_LAYOUT_UNDEFINED: barrier.srcAccessMask = VkAccessFlags 0
of VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier.srcAccessMask = VkAccessFlags VK_ACCESS_TRANSFER_WRITE_BIT
sourceStage = VkPipelineStageFlags VK_PIPELINE_STAGE_TRANSFER_BIT
of VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier.srcAccessMask = VkAccessFlags VK_ACCESS_SHADER_READ_BIT
sourceStage = VkPipelineStageFlags VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
else: quit("unsupported image transition12")
case newLayout:
of VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier.dstAccessMask = VkAccessFlags VK_ACCESS_TRANSFER_WRITE_BIT
destinationStage = VkPipelineStageFlags VK_PIPELINE_STAGE_TRANSFER_BIT
of VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier.srcAccessMask = VkAccessFlags VK_ACCESS_TRANSFER_WRITE_BIT
barrier.dstAccessMask = VkAccessFlags VK_ACCESS_SHADER_READ_BIT
destinationStage = VkPipelineStageFlags VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
else: quit("unsupported image transition13")
vkCmdPipelineBarrier(cmdBuffer, sourceStage, destinationStage, VkDependencyFlags 0, uint32 0, nil, uint32 0, nil, uint32 1, addr barrier )
endSingleTimeCommands( rec.vk_device
, cmdBuffer
, rec.graphics_queue
, rec.command_pool
)
proc createTextureDescrSet*( rec: Vulkan_Record
, ta: var TextureAtlas
): VkDescriptorSet =
var
descriptorSet: VkDescriptorSet
allocInfo = VkDescriptorSetAllocateInfo( sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO
, descriptorPool: ta.descPool
, descriptorSetCount: 1
, pSetLayouts: addr ta.descrSetLayout
)
discard vkAllocateDescriptorSets( rec.vk_device
, addr allocInfo
, addr descriptorSet
)
var
imageInfo = VkDescriptorImageInfo( imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
, imageView: ta.imageView
, sampler: ta.sampler
)
descriptorWrites = VkWriteDescriptorSet( sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET
, dstSet: descriptorSet
, dstBinding: 0
, dstArrayElement: 0
, descriptorType: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
, descriptorCount: 1
, pImageInfo: addr imageInfo
)
vkUpdateDescriptorSets( rec.vk_device
, u321
, addr descriptorWrites
, u320
, nil
)
result
proc aTextureAtlas*( rec: var Vulkan_Record
, width, height: uint32
, format = VK_FORMAT_R8G8B8A8_UNORM
): TextureAtlas =
result.width = width
result.height = height
result.boundImage = createImage( rec.vk_device
, rec.gpu.memory_properties
, result.width
, result.height
, format
, VK_IMAGE_TILING_OPTIMAL
, VkImageUsageFlags bitor( VK_IMAGE_USAGE_TRANSFER_DST_BIT.ord
, VK_IMAGE_USAGE_SAMPLED_BIT.ord
)
, VkMemoryPropertyFlags VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT.ord
)
rec.transitionImageLayout( result.boundImage.image
, VK_IMAGE_LAYOUT_UNDEFINED
, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
)
rec.transitionImageLayout( result.boundImage.image
, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
)
result.imageView = rec.vk_device.createImageView(result.boundImage.image, format)
result.sampler = rec.vk_device.createSampler
result.descrSet = rec.createTextureDescrSet result
]#
projection*: Mat4f
model*: Mat4f
view*: Mat4f
model_view_projection*: Mat4[float32]
being_color*: Vec4[float32]
deshn_color*: Vec4[float32]
pos*: Vec4[float32]
projection*: Mat4
model*: Mat4
view*: Mat4
model_view_projection*: Mat4
being_color*: Vec4
deshn_color*: Vec4
pos*: Vec4
, pipeline_record: Pipeline_Record
, render_pass: VkRenderPass
, current_enitity_id: int
#, s: var Scene # TODO: DO NOT DELET
, sides: Natural
, name: string
, the_size: Vec2[float32]
, being_color: Vec4[float32] = vec4f(1.0, 0.0, 0.0, 1.0)
, deshn_color: Vec4[float32] = vec4f(1.0, 0.0, 0.0, 1.0)
, camera_type: Camera_Kind = Ortho
, hollow: bool = false
# TODO: custom vertices and indices
# , vertices: seq[seq[seq[float32]
# , indices seq[float32]
): Shape =
, current_enitity_id: int
#, s: var Scene # TODO: DO NOT DELET
, sides: Natural
, name: string
, the_size: Vec2
, being_color: Vec4 = vec4(1.0, 0.0, 0.0, 1.0)
, deshn_color: Vec4 = vec4(1.0, 0.0, 0.0, 1.0)
, camera_type: Camera_Kind = Ortho
, hollow: bool = false
# TODO: custom vertices and indices
# , vertices: seq[seq[seq[float32]
# , indices seq[float32]
): Shape =
, camera: a_camera ( (float vulkan_record.swapchain.current_extent.width) /
(float vulkan_record.swapchain.current_extent.height)
)
#[ , camera: a_camera ( (float vulkan_record.swapchain.current_extent.width) /
(float vulkan_record.swapchain.current_extent.height)
) ]#
case result.camera_kind:
of Perspective:
result.ubo.projection = vkm.perspectiveLH( 90.0'f32
, vulkan_record.swapchain.current_extent.width.float32 /
vulkan_record.swapchain.current_extent.height.float32
, 1.0.float32
, 1000.0.float32
)
result.ubo.model = mat4f(1.float32)
.scale( result.the_size.x
, result.the_size.y
, 0.0
)
.translate(0.float32,0,0)
result.ubo.view = lookAt( vec3f( 0.0
, 0.0
, 0.0
)
, vec3f( 0.0
, 0.0
, 0.0
)
, vec3f( 0.0
, 0.0
, 0.0
)
of Ortho:
result.ubo.projection = vkm.ortho( 0.float32
, vulkan_record.swapchain.current_extent.width.float32
, 0.float32
, vulkan_record.swapchain.current_extent.height.float32
, 0.0.float32
, -1000.0.float32
)
result.ubo.model = mat4f(1.float32)
.scale( result.the_size.x
, result.the_size.y
, 0.0
)
#.translate(0.float32,0,0)
.rotate( radians 180'f32, 1, 0, 0)
result.ubo.view = mat4f(1)# lookAtRH( vec3( 1280.float32 / 2, 1280.float32, 1.0)
#, vec3(0f, 0.0, 0)
#, vec3(0f, 0, 1)
#)
)
#vulkan_record.prepare_uniform_buffers result
#vulkan_record.vk_device.updateCamera shape
# actions
proc update_model_view_projection*( shape: var Shape
) =
shape.ubo.model_view_projection = shape.camera.matrices.perspective *
shape.camera.matrices.view *
shape.ubo.model
proc scale*( t: var Shape
, x: float32
, y: float32
) =
var
posX = t.ubo.model[3][0]
posY = t.ubo.model[3][1]
t.ubo.model = mat4f(1)
#.scale(x,y,1)
.translate(posX, posY, 0)
t.ubo.model = t.ubo.model.scale( t.the_size.x * x
, t.the_size.y * y
, 0.0
)
t.update_model_view_projection()
# vulkan is y neg
proc move_up*( t: var Shape
, y: float32
#, x: float32
) =
t.camera.translate(normalize vec3f(0.0,-y,0.0))
t.update_model_view_projection()
# vulkan is y neg
proc move_down*( t: var Shape
, y: float32
#, x: float32
) =
t.camera.translate(normalize vec3f( 0.0, y,0.0))
# .rotate(radians 180.0, 1, 0, 0 )
#.scale(t.the_size)
t.update_model_view_projection()
# vulkan is y neg
proc move_left*( t: var Shape
, x: float32
#, y: float32
) =
t.camera.translate(normalize vec3f(-x,0.0,0.0))
# .rotate(radians 180.0, 1, 0, 0 )
#.scale(t.the_size)
t.update_model_view_projection()
# vulkan is y neg
proc move_right*( t: var Shape
, x: float32
#, y: float32
) =
t.camera.translate(normalize vec3f(x,0.0,0.0))
# .rotate(radians 180.0, 1, 0, 0 )
#.scale(t.the_size)
t.update_model_view_projection()
proc move_up2*( t: var Shape
, y: float32
#, x: float32
) =
t.ubo.model = t.ubo.model
.translate(normalize vec3f(0.0,y,0.0))
t.update_model_view_projection()
# vulkan is y neg
proc move_down2*( t: var Shape
, y: float32
#, x: float32
) =
t.ubo.model = t.ubo.model
.translate(normalize vec3f( 0.0, -y,0.0))
# .rotate(radians 180.0, 1, 0, 0 )
#.scale(t.the_size)
t.update_model_view_projection()
# vulkan is y neg
proc move_left2*( t: var Shape
, x: float32
#, y: float32
) =
t.ubo.model = t.ubo.model
.translate(normalize vec3f(-x,0.0,0.0))
# .rotate(radians 180.0, 1, 0, 0 )
#.scale(t.the_size)
t.update_model_view_projection()
# vulkan is y neg
proc move_right2*( t: var Shape
, x: float32
#, y: float32
) =
t.ubo.model = t.ubo.model
.translate(normalize vec3f(x,0.0,0.0))
# .rotate(radians 180.0, 1, 0, 0 )
#.scale(t.the_size)
t.update_model_view_projection()
# vulkan is y neg
proc move_to*( t: var Shape
, x: float32
, y: float32
) =
t.ubo.model = mat4f(1)
.translate(0,0,0)
.translate(x,-y,0)
# .rotate(radians 180.0, 1, 0, 0 )
.scale( t.the_size.x
, t.the_size.y
, 0.0
)
t.update_model_view_projection()
#[ proc updateCamera*( shape: var Shape
) =
# if text.camera_type == Ortho:
#text.ubos.vs.view = text.camera.matrices.view
#text.camera.updateViewMatrix()
# if text.camera_type == Perspective:
# text.ubos.vs.projection = text.camera.matrices.persp
# text.ubos.vs.view = text.camera.matrices.view
# text.ubos.vs.model = mat4(1.0.float32).scale 0.16
# text.camera.updateViewMatrix()
shape.vk_device[].map_memory( shape.uniform_buffer.memory
, shape.uniform_buffer.data
)
shape.vk_device[].map_memory( shape.uniform_buffer.memory
, shape.uniform_buffer.data
)
copymem(shape.uniform_buffer.data, addr shape.ubo, shape.ubo.sizeof)
copymem(shape.uniform_buffer.data, addr shape.ubo, shape.ubo.sizeof)
vkUnmapMemory(shape.vk_device[], shape.uniform_buffer.memory)
vkUnmapMemory(shape.vk_device[], shape.uniform_buffer.memory)
#shape.changed = false ]#
)
proc move_to*( being: var Deshn_Being
, x
, y: float32
) = being.shape.move_to( x
, y
)
proc move_up*( being: var Deshn_Being
, amount: float32
, deshn_cost = 0.1
) =
if being.can_move:
being.shape.move_up amount
being.process_event Main_Deshn_Being_Events.Moved
being.remove_amount_from_deshn_pool 0.03
else: discard
proc move_down*( being: var Deshn_Being
, amount: float32
, deshn_cost = 0.1
) =
if being.can_move:
being.shape.move_down amount
being.process_event Main_Deshn_Being_Events.Moved
being.remove_amount_from_deshn_pool 0.03
else: discard
proc move_left*( being: var Deshn_Being
, amount: float32
, deshn_cost = 0.1
) =
if being.can_move:
being.shape.move_left amount
being.process_event Main_Deshn_Being_Events.Moved
being.remove_amount_from_deshn_pool 0.03
else: discard
flip_Y*: bool
proc update_view_matrix*( camera: var Camera
) =
var
rotation_matrix = mat4 1.0f
translation_matrix: Mat4[float32]
camera_flip_mod = if camera.flipY: -1.0f else: 1.0f
translation = camera.position
rotation_matrix = rotate( rotation_matrix
, radians(camera.rotation.x *
camera_flip_mod
)
, vec3( 1.0f
, 0.0f
, 0.0f
)
)
rotation_matrix = rotate( rotation_matrix
, radians(camera.rotation.y)
, vec3( 0.0f
, 1.0f
, 0.0f)
);
rotation_matrix = rotate( rotation_matrix
, radians(camera.rotation.z)
, vec3( 0.0f
, 0.0f
, 1.0f)
);
if camera.flipY: translation.y *= -1.0f
translation_matrix = translate( mat4(1.0f)
, translation
)
# if (type == CameraType::firstperson)
# {
# matrices.view = rotation_matrix * translation_matrix;
# }
# else
# {
camera.matrices.view = translation_matrix * rotation_matrix;
# }
camera.view_position = vec4( camera.position
, 0.0f
) *
vec4( -1.0f
, 1.0f
, -1.0f
, 1.0f
)
camera.updated = true
proc `set_perspective_with`*( c: var Camera
, fov
, aspect
, z_near
, z_far: float32
) =
c.fov = fov
c.z_near = z_near
c.z_far = z_far
c.matrices.perspective = perspective( radians fov
, aspect
, z_near
, z_far
)
if (c.flipY): c.matrices.perspective[1][1] *= -1f
proc `position_is`*( c: var Camera
, position: Vec3[float32]
) =
c.position = position
c.update_view_matrix
proc `position+=`*( c: var Camera
, position: Vec3[float32]
) =
c.position += position
c.update_view_matrix
proc `rotation=`*( c: var Camera
, rot: Vec3[float32]
) =
c.rotation = rot
proc translate*( c: var Camera
, vector: Vec3[float32]
) =
c.position += vector
c.update_view_matrix()
proc update*( camera: var Camera
, dt: float
) =
camera.updated = false
proc `set_aspect_ratio_with`*( c: var Camera
, fov, ar: float32
) =
c.set_perspective_with radians(fov), ar, 1, 256.0
#c.update_view_matrix()
proc a_camera*( ar: float32
, camera_type: Camera_Kind = Perspective
): Camera =
case camera_type
of Ortho: discard
of Perspective: discard
result.position = vec3f( 0.0.float32
, 0.0
, 0.0
)
result.rotation = vec3f(0.float32)
result.set_perspective_with( 90.0.float32
, ar
, 1.0
, 256.0
)
result.update_view_matrix()
result
flip_Y*: bool
type
Alternative_Seq*[T] = object
length*: int
, capacity*: int
data*: ptr UncheckedArray[T]
proc `=destroy`*[T](x: Alternative_Seq[T]) =
if x.data != nil:
for i in 0..<x.len: `=destroy`(x.data[i])
dealloc(x.data)
proc `=trace`[T](x: var Alternative_Seq[T]; env: pointer) =
# `=trace` allows the cycle collector `--mm:orc`
# to understand how to trace the object graph.
if x.data != nil:
for i in 0..<x.len: `=trace`(x.data[i], env)
proc `=copy`*[T](a: var Alternative_Seq[T]; b: Alternative_Seq[T]) =
# do nothing for self-assignments:
if a.data == b.data: return
`=destroy`(a)
wasMoved(a)
a.len = b.len
a.cap = b.cap
if b.data != nil:
a.data = cast[typeof(a.data)](alloc(a.cap * sizeof(T)))
for i in 0..<a.len:
a.data[i] = b.data[i]
proc `=dup`*[T](a: Alternative_Seq[T]): Alternative_Seq[T] {.nodestroy.} =
# an optimized version of `=wasMoved(tmp); `=copy(tmp, src)`
# usually present if a custom `=copy` hook is overridden
result.len = a.len
result.cap = a.cap
if a.data != nil:
result.data = cast[typeof(result.data)](alloc(result.cap * sizeof(T)))
for i in 0..<result.len:
result.data[i] = `=dup`(a.data[i])
proc `=sink`*[T](a: var Alternative_Seq[T]; b: Alternative_Seq[T]) =
# move assignment, optional.
# Compiler is using `=destroy` and `copyMem` when not provided
`=destroy`(a)
wasMoved(a)
a.len = b.len
a.cap = b.cap
a.data = b.data
proc add*[T](x: var Alternative_Seq[T]; y: sink T) =
if x.len >= x.cap:
x.cap = max(x.len + 1, x.cap * 2)
x.data = cast[typeof(x.data)](realloc(x.data, x.cap * sizeof(T)))
x.data[x.len] = y
inc x.len
proc `[]`*[T](x: Alternative_Seq[T]; i: Natural): lent T =
assert i < x.len
x.data[i]
proc `[]=`*[T](x: var Alternative_Seq[T]; i: Natural; y: sink T) =
assert i < x.len
x.data[i] = y
proc an_alternative_seq*[T](elems: varargs[T]): Alternative_Seq[T] =
result.cap = elems.len
result.len = elems.len
result.data = cast[typeof(result.data)](alloc(result.cap * sizeof(T)))
for i in 0..<result.len: result.data[i] = elems[i]
proc len*[T](x: Alternative_Seq[T]): int {.inline.} = x.len