changeset 147:3dffa1f38a33

del: legacy
author Sam <sam@basx.dev>
date Thu, 27 Apr 2023 00:24:10 +0700
parents 253dd797e719
children ae8b0d89a2ee
files src/semicongine/legacy/buffer.nim src/semicongine/legacy/descriptor.nim src/semicongine/legacy/engine.nim src/semicongine/legacy/glsl.nim src/semicongine/legacy/glsl_helpers.nim src/semicongine/legacy/image.nim src/semicongine/legacy/shader.nim src/semicongine/legacy/thing.nim src/semicongine/legacy/vertex.nim src/semicongine/legacy/vulkan_helpers.nim
diffstat 10 files changed, 0 insertions(+), 2005 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/legacy/buffer.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-import std/typetraits
-
-import ./vulkan
-import ./vulkan_helpers
-
-type
-  BufferType* = enum
-    None = 0
-    TransferSrc = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
-    TransferDst = VK_BUFFER_USAGE_TRANSFER_DST_BIT
-    UniformBuffer = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
-    IndexBuffer = VK_BUFFER_USAGE_INDEX_BUFFER_BIT
-    VertexBuffer = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
-  MemoryProperty* = enum
-    DeviceLocal = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
-    HostVisible = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
-    HostCoherent = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
-  MemoryProperties* = set[MemoryProperty]
-  Buffer* = object
-    device*: VkDevice
-    vkBuffer*: VkBuffer
-    size*: uint64
-    memoryRequirements*: VkMemoryRequirements
-    memoryProperties*: MemoryProperties
-    memory*: VkDeviceMemory
-    bufferTypes*: set[BufferType]
-    data*: pointer
-
-proc trash*(buffer: var Buffer) =
-  if int64(buffer.vkBuffer) != 0 and int64(buffer.memory) != 0:
-    vkUnmapMemory(buffer.device, buffer.memory)
-  if int64(buffer.vkBuffer) != 0:
-    vkDestroyBuffer(buffer.device, buffer.vkBuffer, nil)
-    buffer.vkBuffer = VkBuffer(0)
-  if int64(buffer.memory) != 0:
-    vkFreeMemory(buffer.device, buffer.memory, nil)
-    buffer.memory = VkDeviceMemory(0)
-
-proc findMemoryType*(memoryRequirements: VkMemoryRequirements,
-    physicalDevice: VkPhysicalDevice, properties: MemoryProperties): uint32 =
-  var physicalProperties: VkPhysicalDeviceMemoryProperties
-  vkGetPhysicalDeviceMemoryProperties(physicalDevice, addr(physicalProperties))
-
-  for i in 0'u32 ..< physicalProperties.memoryTypeCount:
-    if bool(memoryRequirements.memoryTypeBits and (1'u32 shl i)):
-      if (uint32(physicalProperties.memoryTypes[i].propertyFlags) and cast[
-          uint32](properties)) == cast[uint32](properties):
-        return i
-
-proc InitBuffer*(
-  device: VkDevice,
-  physicalDevice: VkPhysicalDevice,
-  size: uint64,
-  bufferTypes: set[BufferType],
-  properties: MemoryProperties,
-): Buffer =
-  result = Buffer(device: device, size: size, bufferTypes: bufferTypes, memoryProperties: properties)
-  var usageFlags = 0
-  for usage in bufferTypes:
-    usageFlags = ord(usageFlags) or ord(usage)
-  var bufferInfo = VkBufferCreateInfo(
-    sType: VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
-    size: VkDeviceSize(result.size),
-    usage: VkBufferUsageFlags(usageFlags),
-    sharingMode: VK_SHARING_MODE_EXCLUSIVE,
-  )
-  checkVkResult vkCreateBuffer(result.device, addr(bufferInfo), nil, addr(result.vkBuffer))
-  vkGetBufferMemoryRequirements(result.device, result.vkBuffer, addr(result.memoryRequirements))
-
-  var allocInfo = VkMemoryAllocateInfo(
-    sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
-    allocationSize: result.memoryRequirements.size,
-    memoryTypeIndex: result.memoryRequirements.findMemoryType(physicalDevice, properties)
-  )
-  if result.size > 0:
-    checkVkResult result.device.vkAllocateMemory(addr(allocInfo), nil, addr(result.memory))
-  checkVkResult result.device.vkBindBufferMemory(result.vkBuffer, result.memory, VkDeviceSize(0))
-  checkVkResult vkMapMemory(
-    result.device,
-    result.memory,
-    offset = VkDeviceSize(0),
-    VkDeviceSize(result.size),
-    VkMemoryMapFlags(0),
-    addr(result.data)
-  )
-
-
-proc transferBuffer*(commandPool: VkCommandPool, queue: VkQueue, src, dst: Buffer, size: uint64) =
-  assert uint64(src.device) == uint64(dst.device)
-  assert TransferSrc in src.bufferTypes
-  assert TransferDst in dst.bufferTypes
-  var
-    allocInfo = VkCommandBufferAllocateInfo(
-      sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
-      level: VK_COMMAND_BUFFER_LEVEL_PRIMARY,
-      commandPool: commandPool,
-      commandBufferCount: 1,
-    )
-    commandBuffer: VkCommandBuffer
-  checkVkResult vkAllocateCommandBuffers(src.device, addr(allocInfo), addr(commandBuffer))
-
-  var beginInfo = VkCommandBufferBeginInfo(
-    sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
-    flags: VkCommandBufferUsageFlags(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT),
-  )
-  checkVkResult vkBeginCommandBuffer(commandBuffer, addr(beginInfo))
-  var copyRegion = VkBufferCopy(size: VkDeviceSize(size))
-  vkCmdCopyBuffer(commandBuffer, src.vkBuffer, dst.vkBuffer, 1, addr(copyRegion))
-  checkVkResult vkEndCommandBuffer(commandBuffer)
-
-  var submitInfo = VkSubmitInfo(
-    sType: VK_STRUCTURE_TYPE_SUBMIT_INFO,
-    commandBufferCount: 1,
-    pCommandBuffers: addr(commandBuffer),
-  )
-
-  checkVkResult vkQueueSubmit(queue, 1, addr(submitInfo), VkFence(0))
-  checkVkResult vkQueueWaitIdle(queue)
-  vkFreeCommandBuffers(src.device, commandPool, 1, addr(commandBuffer))
-
--- a/src/semicongine/legacy/descriptor.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-import std/strutils
-import std/unicode
-import std/strformat
-import std/typetraits
-
-import ./vulkan
-import ./vulkan_helpers
-import ./math/vector
-import ./math/matrix
-import ./buffer
-import ./glsl_helpers
-
-# TODO: check for alignment in uniform blocks
-#
-type
-  DescriptorType = SomeNumber|TVec|TMat
-  Descriptor*[T: DescriptorType] = object
-    value*: T
-  ViewProjectionTransform* = Descriptor[Mat44]
-
-proc createUniformDescriptorLayout*(device: VkDevice,
-    shaderStage: VkShaderStageFlags, binding: uint32): VkDescriptorSetLayout =
-  var
-    layoutbinding = VkDescriptorSetLayoutBinding(
-      binding: binding,
-      descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-      descriptorCount: 1,
-      stageFlags: shaderStage,
-      pImmutableSamplers: nil,
-    )
-    layoutInfo = VkDescriptorSetLayoutCreateInfo(
-      sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
-      bindingCount: 1,
-      pBindings: addr(layoutbinding)
-    )
-  checkVkResult device.vkCreateDescriptorSetLayout(addr(layoutInfo), nil, addr(result))
-
-proc createUniformBuffers*[nBuffers: static int, Uniforms](device: VkDevice,
-    physicalDevice: VkPhysicalDevice): array[nBuffers, Buffer] =
-  let size = sizeof(Uniforms)
-  for i in 0 ..< nBuffers:
-    var buffer = InitBuffer(
-      device,
-      physicalDevice,
-      uint64(size),
-      {UniformBuffer},
-      {HostVisible, HostCoherent},
-    )
-    result[i] = buffer
-
-template getDescriptorType*(v: Descriptor): auto = get(genericParams(typeof(v)), 0)
-
-func generateGLSLUniformDeclarations*[Uniforms](binding: int = 0): string {.compileTime.} =
-  var stmtList: seq[string]
-
-  when not (Uniforms is void):
-    let uniformTypeName = name(Uniforms).toUpper()
-    let uniformInstanceName = name(Uniforms).toLower()
-    stmtList.add(&"layout(binding = {binding}) uniform {uniformTypeName} {{")
-    for fieldname, value in Uniforms().fieldPairs:
-      when typeof(value) is Descriptor:
-        let glsltype = getGLSLType[getDescriptorType(value)]()
-        let n = fieldname
-        stmtList.add(&"    {glsltype} {n};")
-    stmtList.add(&"}} {uniformInstanceName};")
-
-  return stmtList.join("\n")
--- a/src/semicongine/legacy/engine.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,870 +0,0 @@
-import std/options
-import std/os
-import std/times
-import std/typetraits
-import std/strformat
-import std/enumerate
-import std/logging
-
-
-import ./math/vector
-import ./vulkan
-import ./vulkan_helpers
-import ./platform/window
-import ./events
-import ./shader
-import ./vertex
-import ./buffer
-import ./thing
-import ./descriptor
-import ./mesh
-
-const MAX_FRAMES_IN_FLIGHT = 2
-const DEBUG_LOG = not defined(release)
-
-var logger = newConsoleLogger()
-addHandler(logger)
-
-
-const VULKAN_VERSION = VK_MAKE_API_VERSION(0'u32, 1'u32, 2'u32, 0'u32)
-const ENGINE_NAME = "zamkongine"
-const ENGINE_VERSION = "0.1"
-const BUILD_VERSION = ENGINE_VERSION & '-' & gorge("git log -1 --format=format:'%H'")
-echo "Engine: " & ENGINE_NAME & " " & BUILD_VERSION
-
-type
-  Device = object
-    device*: VkDevice
-    physicalDevice*: PhysicalDevice
-    graphicsQueueFamily*: uint32
-    presentationQueueFamily*: uint32
-    graphicsQueue*: VkQueue
-    presentationQueue*: VkQueue
-    commandPool*: VkCommandPool
-    commandBuffers*: array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer]
-  Swapchain = object
-    swapchain: VkSwapchainKHR
-    images: seq[VkImage]
-    imageviews: seq[VkImageView]
-  RenderPipeline*[VertexType, Uniforms] = object
-    device*: VkDevice
-    shaders*: seq[ShaderProgram[VertexType, Uniforms]]
-    layout*: VkPipelineLayout
-    pipeline*: VkPipeline
-    vertexBuffers*: seq[(seq[Buffer], bool, Buffer, uint32, VkIndexType)]
-    descriptorSetLayout*: VkDescriptorSetLayout
-    uniformBuffers*: array[MAX_FRAMES_IN_FLIGHT, Buffer]
-    descriptorPool*: VkDescriptorPool
-    descriptors: array[MAX_FRAMES_IN_FLIGHT, VkDescriptorSet]
-    clearColor*: Vec4
-  QueueFamily = object
-    properties*: VkQueueFamilyProperties
-    hasSurfaceSupport*: bool
-  PhysicalDevice = object
-    device*: VkPhysicalDevice
-    extensions*: seq[string]
-    properties*: VkPhysicalDeviceProperties
-    features*: VkPhysicalDeviceFeatures
-    queueFamilies*: seq[QueueFamily]
-    formats: seq[VkSurfaceFormatKHR]
-    presentModes: seq[VkPresentModeKHR]
-  Vulkan* = object
-    debugMessenger*: VkDebugUtilsMessengerEXT
-    instance*: VkInstance
-    deviceList*: seq[PhysicalDevice]
-    device*: Device
-    surface*: VkSurfaceKHR
-    surfaceFormat*: VkSurfaceFormatKHR
-    frameSize*: TVec2[uint32]
-    swapchain*: Swapchain
-    framebuffers*: seq[VkFramebuffer]
-    renderPass*: VkRenderPass
-    imageAvailableSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore]
-    renderFinishedSemaphores*: array[MAX_FRAMES_IN_FLIGHT, VkSemaphore]
-    inFlightFences*: array[MAX_FRAMES_IN_FLIGHT, VkFence]
-  Input* = object
-    keysDown*: set[Key]
-    keysPressed*: set[Key]
-    keysReleased*: set[Key]
-    mouseDown*: set[MouseButton]
-    mousePressed*: set[MouseButton]
-    mouseReleased*: set[MouseButton]
-    mousePos*: Vec2
-  Engine* = object
-    vulkan*: Vulkan
-    window*: NativeWindow
-    currentscenedata*: Thing
-    input*: Input
-    maxFPS*: uint
-
-
-method update*(thing: Thing, engine: Engine, t, dt: float32) {.base.} = discard
-method update*(part: Part, engine: Engine, t, dt: float32) {.base.} = discard
-
-method update*[T, U](mesh: Mesh[T, U], engine: Engine, t, dt: float32) =
-  let transform = @[mesh.thing.getModelTransform().transposed()]
-  for name, value in mesh.vertexData.fieldPairs:
-    when value is ModelTransformAttribute:
-      value.data = transform
-      engine.vulkan.device.updateVertexData(value)
-
-proc getAllPhysicalDevices(instance: VkInstance, surface: VkSurfaceKHR): seq[
-    PhysicalDevice] =
-  for vulkanPhysicalDevice in getVulkanPhysicalDevices(instance):
-    var device = PhysicalDevice(device: vulkanPhysicalDevice, extensions: vulkan.getDeviceExtensions(vulkanPhysicalDevice))
-    vkGetPhysicalDeviceProperties(vulkanPhysicalDevice, addr(device.properties))
-    vkGetPhysicalDeviceFeatures(vulkanPhysicalDevice, addr(device.features))
-    device.formats = vulkanPhysicalDevice.getDeviceSurfaceFormats(surface)
-    device.presentModes = vulkanPhysicalDevice.getDeviceSurfacePresentModes(surface)
-
-    debug(&"Physical device nr {int(vulkanPhysicalDevice)} {cleanString(device.properties.deviceName)}")
-    for i, queueFamilyProperty in enumerate(getQueueFamilies(vulkanPhysicalDevice)):
-      var hasSurfaceSupport: VkBool32 = VK_FALSE
-      checkVkResult vkGetPhysicalDeviceSurfaceSupportKHR(vulkanPhysicalDevice, uint32(i), surface, addr(hasSurfaceSupport))
-      device.queueFamilies.add(QueueFamily(properties: queueFamilyProperty, hasSurfaceSupport: bool(hasSurfaceSupport)))
-      debug(&"  Queue family {i} {queueFamilyProperty}")
-
-    result.add(device)
-
-proc filterForDevice(devices: seq[PhysicalDevice]): seq[(PhysicalDevice, uint32, uint32)] =
-  for device in devices:
-    if not (device.formats.len > 0 and device.presentModes.len > 0 and "VK_KHR_swapchain" in device.extensions):
-      continue
-    var graphicsQueueFamily = high(uint32)
-    var presentationQueueFamily = high(uint32)
-    for i, queueFamily in enumerate(device.queueFamilies):
-      if queueFamily.hasSurfaceSupport:
-        presentationQueueFamily = uint32(i)
-      if bool(uint32(queueFamily.properties.queueFlags) and ord(VK_QUEUE_GRAPHICS_BIT)):
-        graphicsQueueFamily = uint32(i)
-    if graphicsQueueFamily != high(uint32) and presentationQueueFamily != high(uint32):
-      result.add((device, graphicsQueueFamily, presentationQueueFamily))
-
-  for (device, graphicsQueueFamily, presentationQueueFamily) in result:
-    debug(&"Viable device: {cleanString(device.properties.deviceName)} (graphics queue family {graphicsQueueFamily}, presentation queue family {presentationQueueFamily})")
-
-
-proc getFrameDimension(window: NativeWindow, device: VkPhysicalDevice,
-    surface: VkSurfaceKHR): TVec2[uint32] =
-  let capabilities = device.getSurfaceCapabilities(surface)
-  if capabilities.currentExtent.width != high(uint32):
-    return TVec2[uint32]([capabilities.currentExtent.width,
-        capabilities.currentExtent.height])
-  else:
-    let (width, height) = window.size()
-    return TVec2[uint32]([
-      min(max(uint32(width), capabilities.minImageExtent.width),
-          capabilities.maxImageExtent.width),
-      min(max(uint32(height), capabilities.minImageExtent.height),
-          capabilities.maxImageExtent.height),
-    ])
-
-when DEBUG_LOG:
-  proc setupDebugLog(instance: VkInstance): VkDebugUtilsMessengerEXT =
-    var createInfo = VkDebugUtilsMessengerCreateInfoEXT(
-      sType: VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
-      messageSeverity: VkDebugUtilsMessageSeverityFlagsEXT(
-        ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) or
-        ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) or
-        ord(VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
-      ),
-      messageType: VkDebugUtilsMessageTypeFlagsEXT(
-        ord(VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) or
-        ord(VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) or
-        ord(VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
-      ),
-      pfnUserCallback: debugCallback,
-      pUserData: nil,
-    )
-    checkVkResult instance.vkCreateDebugUtilsMessengerEXT(addr(createInfo), nil, addr(result))
-
-proc setupVulkanDeviceAndQueues(instance: VkInstance, surface: VkSurfaceKHR): Device =
-  let usableDevices = instance.getAllPhysicalDevices(surface).filterForDevice()
-  if len(usableDevices) == 0:
-    raise newException(Exception, "No suitable graphics device found")
-  result.physicalDevice = usableDevices[0][0]
-  result.graphicsQueueFamily = usableDevices[0][1]
-  result.presentationQueueFamily = usableDevices[0][2]
-
-  debug(&"Chose device {cleanString(result.physicalDevice.properties.deviceName)}")
-
-  (result.device, result.graphicsQueue, result.presentationQueue) = getVulcanDevice(
-    result.physicalDevice.device,
-    result.physicalDevice.features,
-    result.graphicsQueueFamily,
-    result.presentationQueueFamily,
-  )
-
-proc setupSwapChain(device: VkDevice, physicalDevice: PhysicalDevice, surface: VkSurfaceKHR, dimension: TVec2[uint32], surfaceFormat: VkSurfaceFormatKHR): Swapchain =
-
-  let capabilities = physicalDevice.device.getSurfaceCapabilities(surface)
-  var selectedPresentationMode = getPresentMode(physicalDevice.presentModes)
-  var imageCount = capabilities.minImageCount + 1
-  if capabilities.maxImageCount > 0:
-    imageCount = min(capabilities.maxImageCount, imageCount)
-  # TODO: something not working on window..., likely the extent
-  var extent = VkExtent2D(
-    width: if dimension[0] > 0: dimension[0] else: 1,
-    height: if dimension[1] > 0: dimension[1] else: 1,
-  )
-  # setup swapchain
-  var swapchainCreateInfo = VkSwapchainCreateInfoKHR(
-    sType: VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
-    surface: surface,
-    minImageCount: imageCount,
-    imageFormat: surfaceFormat.format,
-    imageColorSpace: surfaceFormat.colorSpace,
-    imageExtent: extent,
-    imageArrayLayers: 1,
-    imageUsage: VkImageUsageFlags(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT),
-    # VK_SHARING_MODE_CONCURRENT no supported (i.e cannot use different queue families for drawing to swap surface?)
-    imageSharingMode: VK_SHARING_MODE_EXCLUSIVE,
-    preTransform: capabilities.currentTransform,
-    compositeAlpha: VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
-    presentMode: selectedPresentationMode,
-    clipped: VK_TRUE,
-    oldSwapchain: VkSwapchainKHR(0),
-  )
-  checkVkResult device.vkCreateSwapchainKHR(addr(swapchainCreateInfo), nil,
-      addr(result.swapchain))
-  result.images = device.getSwapChainImages(result.swapchain)
-
-  # setup swapchian image views
-
-  result.imageviews = newSeq[VkImageView](result.images.len)
-  for i, image in enumerate(result.images):
-    var imageViewCreateInfo = VkImageViewCreateInfo(
-      sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
-      image: image,
-      viewType: VK_IMAGE_VIEW_TYPE_2D,
-      format: surfaceFormat.format,
-      components: VkComponentMapping(
-        r: VK_COMPONENT_SWIZZLE_IDENTITY,
-        g: VK_COMPONENT_SWIZZLE_IDENTITY,
-        b: VK_COMPONENT_SWIZZLE_IDENTITY,
-        a: VK_COMPONENT_SWIZZLE_IDENTITY,
-      ),
-      subresourceRange: VkImageSubresourceRange(
-        aspectMask: VkImageAspectFlags(VK_IMAGE_ASPECT_COLOR_BIT),
-        baseMipLevel: 0,
-        levelCount: 1,
-        baseArrayLayer: 0,
-        layerCount: 1,
-      ),
-    )
-    checkVkResult device.vkCreateImageView(addr(imageViewCreateInfo), nil, addr(result.imageviews[i]))
-
-proc setupRenderPass(device: VkDevice, format: VkFormat): VkRenderPass =
-  var
-    colorAttachment = VkAttachmentDescription(
-      format: format,
-      samples: VK_SAMPLE_COUNT_1_BIT,
-      loadOp: VK_ATTACHMENT_LOAD_OP_CLEAR,
-      storeOp: VK_ATTACHMENT_STORE_OP_STORE,
-      stencilLoadOp: VK_ATTACHMENT_LOAD_OP_DONT_CARE,
-      stencilStoreOp: VK_ATTACHMENT_STORE_OP_DONT_CARE,
-      initialLayout: VK_IMAGE_LAYOUT_UNDEFINED,
-      finalLayout: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
-    )
-    colorAttachmentRef = VkAttachmentReference(
-      attachment: 0,
-      layout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
-    )
-    subpass = VkSubpassDescription(
-      pipelineBindPoint: VK_PIPELINE_BIND_POINT_GRAPHICS,
-      colorAttachmentCount: 1,
-      pColorAttachments: addr(colorAttachmentRef)
-    )
-    dependency = VkSubpassDependency(
-      srcSubpass: VK_SUBPASS_EXTERNAL,
-      dstSubpass: 0,
-      srcStageMask: VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT),
-      srcAccessMask: VkAccessFlags(0),
-      dstStageMask: VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT),
-      dstAccessMask: VkAccessFlags(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
-    )
-    renderPassCreateInfo = VkRenderPassCreateInfo(
-      sType: VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
-      attachmentCount: 1,
-      pAttachments: addr(colorAttachment),
-      subpassCount: 1,
-      pSubpasses: addr(subpass),
-      dependencyCount: 1,
-      pDependencies: addr(dependency),
-    )
-  checkVkResult device.vkCreateRenderPass(addr(renderPassCreateInfo), nil, addr(result))
-
-proc initRenderPipeline[VertexType, Uniforms](device: VkDevice, frameSize: TVec2[uint32], renderPass: VkRenderPass, vertexShader, fragmentShader: static string): RenderPipeline[VertexType, Uniforms] =
-  # load shaders
-  result.device = device
-  result.shaders.add(initShaderProgram[VertexType, Uniforms](device, VK_SHADER_STAGE_VERTEX_BIT, vertexShader))
-  result.shaders.add(initShaderProgram[VertexType, Uniforms](device, VK_SHADER_STAGE_FRAGMENT_BIT, fragmentShader))
-
-  var
-    # define which parts can be dynamic (pipeline is fixed after setup)
-    dynamicStates = [VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR]
-    dynamicState = VkPipelineDynamicStateCreateInfo(
-      sType: VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
-      dynamicStateCount: uint32(dynamicStates.len),
-      pDynamicStates: addr(dynamicStates[0]),
-    )
-    vertexbindings = generateInputVertexBinding[VertexType]()
-    attributebindings = generateInputAttributeBinding[VertexType]()
-
-    # define input data format
-    vertexInputInfo = VkPipelineVertexInputStateCreateInfo(
-      sType: VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
-      vertexBindingDescriptionCount: uint32(vertexbindings.len),
-      pVertexBindingDescriptions: addr(vertexbindings[0]),
-      vertexAttributeDescriptionCount: uint32(attributebindings.len),
-      pVertexAttributeDescriptions: addr(attributebindings[0]),
-    )
-    inputAssembly = VkPipelineInputAssemblyStateCreateInfo(
-      sType: VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
-      topology: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
-      primitiveRestartEnable: VK_FALSE,
-    )
-
-  # setup viewport
-  var viewportState = VkPipelineViewportStateCreateInfo(
-    sType: VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
-    viewportCount: 1,
-    scissorCount: 1,
-  )
-
-  # rasterizerization config
-  var
-    rasterizer = VkPipelineRasterizationStateCreateInfo(
-      sType: VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
-      depthClampEnable: VK_FALSE,
-      rasterizerDiscardEnable: VK_FALSE,
-      polygonMode: VK_POLYGON_MODE_FILL,
-      lineWidth: 1.0,
-      cullMode: VkCullModeFlags(VK_CULL_MODE_BACK_BIT),
-      frontFace: VK_FRONT_FACE_CLOCKWISE,
-      depthBiasEnable: VK_FALSE,
-      depthBiasConstantFactor: 0.0,
-      depthBiasClamp: 0.0,
-      depthBiasSlopeFactor: 0.0,
-    )
-    multisampling = VkPipelineMultisampleStateCreateInfo(
-      sType: VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
-      sampleShadingEnable: VK_FALSE,
-      rasterizationSamples: VK_SAMPLE_COUNT_1_BIT,
-      minSampleShading: 1.0,
-      pSampleMask: nil,
-      alphaToCoverageEnable: VK_FALSE,
-      alphaToOneEnable: VK_FALSE,
-    )
-    colorBlendAttachment = VkPipelineColorBlendAttachmentState(
-      colorWriteMask: VkColorComponentFlags(
-        ord(VK_COLOR_COMPONENT_R_BIT) or
-        ord(VK_COLOR_COMPONENT_G_BIT) or
-        ord(VK_COLOR_COMPONENT_B_BIT) or
-        ord(VK_COLOR_COMPONENT_A_BIT)
-      ),
-      blendEnable: VK_TRUE,
-      srcColorBlendFactor: VK_BLEND_FACTOR_SRC_ALPHA,
-      dstColorBlendFactor: VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
-      colorBlendOp: VK_BLEND_OP_ADD,
-      srcAlphaBlendFactor: VK_BLEND_FACTOR_ONE,
-      dstAlphaBlendFactor: VK_BLEND_FACTOR_ZERO,
-      alphaBlendOp: VK_BLEND_OP_ADD,
-    )
-    colorBlending = VkPipelineColorBlendStateCreateInfo(
-      sType: VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
-      logicOpEnable: VK_TRUE,
-      logicOp: VK_LOGIC_OP_COPY,
-      attachmentCount: 1,
-      pAttachments: addr(colorBlendAttachment),
-      blendConstants: [0.0'f, 0.0'f, 0.0'f, 0.0'f],
-    )
-
-  result.descriptorSetLayout = device.createUniformDescriptorLayout(
-      VkShaderStageFlags(VK_SHADER_STAGE_VERTEX_BIT), 0)
-  var
-    # "globals" that go into the shader, uniforms etc.
-    pipelineLayoutInfo = VkPipelineLayoutCreateInfo(
-      sType: VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
-      setLayoutCount: 1,
-      pSetLayouts: addr(result.descriptorSetLayout),
-      pushConstantRangeCount: 0,
-      pPushConstantRanges: nil,
-    )
-  checkVkResult vkCreatePipelineLayout(device, addr(pipelineLayoutInfo), nil, addr(result.layout))
-
-  var stages: seq[VkPipelineShaderStageCreateInfo]
-  for shader in result.shaders:
-    stages.add(shader.shader)
-  var pipelineInfo = VkGraphicsPipelineCreateInfo(
-    sType: VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
-    stageCount: uint32(stages.len),
-    pStages: addr(stages[0]),
-    pVertexInputState: addr(vertexInputInfo),
-    pInputAssemblyState: addr(inputAssembly),
-    pViewportState: addr(viewportState),
-    pRasterizationState: addr(rasterizer),
-    pMultisampleState: addr(multisampling),
-    pDepthStencilState: nil,
-    pColorBlendState: addr(colorBlending),
-    pDynamicState: addr(dynamicState),
-    layout: result.layout,
-    renderPass: renderPass,
-    subpass: 0,
-    basePipelineHandle: VkPipeline(0),
-    basePipelineIndex: -1,
-  )
-  checkVkResult vkCreateGraphicsPipelines(
-    device,
-    VkPipelineCache(0),
-    1,
-    addr(pipelineInfo),
-    nil,
-    addr(result.pipeline)
-  )
-
-proc setupFramebuffers(device: VkDevice, swapchain: var Swapchain,
-    renderPass: VkRenderPass, dimension: TVec2[uint32]): seq[VkFramebuffer] =
-  result = newSeq[VkFramebuffer](swapchain.images.len)
-  for i, imageview in enumerate(swapchain.imageviews):
-    var framebufferInfo = VkFramebufferCreateInfo(
-      sType: VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
-      renderPass: renderPass,
-      attachmentCount: 1,
-      pAttachments: addr(swapchain.imageviews[i]),
-      width: dimension[0],
-      height: dimension[1],
-      layers: 1,
-    )
-    checkVkResult device.vkCreateFramebuffer(addr(framebufferInfo), nil, addr(
-        result[i]))
-
-proc trash(device: VkDevice, swapchain: Swapchain, framebuffers: seq[
-    VkFramebuffer]) =
-  for framebuffer in framebuffers:
-    device.vkDestroyFramebuffer(framebuffer, nil)
-  for imageview in swapchain.imageviews:
-    device.vkDestroyImageView(imageview, nil)
-  device.vkDestroySwapchainKHR(swapchain.swapchain, nil)
-
-proc recreateSwapchain(vulkan: Vulkan): (Swapchain, seq[VkFramebuffer]) =
-  if vulkan.frameSize.x == 0 or vulkan.frameSize.y == 0:
-    return (vulkan.swapchain, vulkan.framebuffers)
-  debug(&"Recreate swapchain with dimension {vulkan.frameSize}")
-  checkVkResult vulkan.device.device.vkDeviceWaitIdle()
-
-  vulkan.device.device.trash(vulkan.swapchain, vulkan.framebuffers)
-
-  result[0] = vulkan.device.device.setupSwapChain(
-    vulkan.device.physicalDevice,
-    vulkan.surface,
-    vulkan.frameSize,
-    vulkan.surfaceFormat
-  )
-  result[1] = vulkan.device.device.setupFramebuffers(
-    result[0],
-    vulkan.renderPass,
-    vulkan.frameSize
-  )
-
-
-proc setupCommandBuffers(device: VkDevice, graphicsQueueFamily: uint32): (
-    VkCommandPool, array[MAX_FRAMES_IN_FLIGHT, VkCommandBuffer]) =
-  # set up command buffer
-  var poolInfo = VkCommandPoolCreateInfo(
-    sType: VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
-    flags: VkCommandPoolCreateFlags(VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT),
-    queueFamilyIndex: graphicsQueueFamily,
-  )
-  checkVkResult device.vkCreateCommandPool(addr(poolInfo), nil, addr(result[0]))
-
-  var allocInfo = VkCommandBufferAllocateInfo(
-    sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
-    commandPool: result[0],
-    level: VK_COMMAND_BUFFER_LEVEL_PRIMARY,
-    commandBufferCount: result[1].len.uint32,
-  )
-  checkVkResult device.vkAllocateCommandBuffers(addr(allocInfo), addr(result[1][0]))
-
-proc setupSyncPrimitives(device: VkDevice): (
-    array[MAX_FRAMES_IN_FLIGHT, VkSemaphore],
-    array[MAX_FRAMES_IN_FLIGHT, VkSemaphore],
-    array[MAX_FRAMES_IN_FLIGHT, VkFence],
-) =
-  var semaphoreInfo = VkSemaphoreCreateInfo(
-      sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO)
-  var fenceInfo = VkFenceCreateInfo(
-    sType: VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
-    flags: VkFenceCreateFlags(VK_FENCE_CREATE_SIGNALED_BIT)
-  )
-  for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
-    checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(
-        result[0][i]))
-    checkVkResult device.vkCreateSemaphore(addr(semaphoreInfo), nil, addr(
-        result[1][i]))
-    checkVkResult device.vkCreateFence(addr(fenceInfo), nil, addr(result[2][i]))
-
-proc igniteEngine*(windowTitle: string): Engine =
-
-  result.window = createWindow(windowTitle)
-  let mousepos = result.window.getMousePosition()
-  if mousepos.isSome():
-    result.input.mousePos = mousePos.get()
-
-
-  # create vulkan instance
-  result.vulkan.instance = createVulkanInstance(VULKAN_VERSION)
-
-  # setup vulkan functions
-  loadVulkan(result.vulkan.instance)
-
-  when DEBUG_LOG:
-    result.vulkan.debugMessenger = result.vulkan.instance.setupDebugLog()
-  result.vulkan.surface = result.vulkan.instance.createVulkanSurface(result.window)
-  result.vulkan.device = result.vulkan.instance.setupVulkanDeviceAndQueues(result.vulkan.surface)
-
-  # get basic frame information
-  result.vulkan.surfaceFormat = result.vulkan.device.physicalDevice.formats.getSuitableSurfaceFormat()
-  result.vulkan.frameSize = result.window.getFrameDimension(result.vulkan.device.physicalDevice.device, result.vulkan.surface)
-
-  # setup swapchain and render pipeline
-  result.vulkan.swapchain = result.vulkan.device.device.setupSwapChain(
-    result.vulkan.device.physicalDevice,
-    result.vulkan.surface,
-    result.vulkan.frameSize,
-    result.vulkan.surfaceFormat
-  )
-  result.vulkan.renderPass = result.vulkan.device.device.setupRenderPass(
-      result.vulkan.surfaceFormat.format)
-  result.vulkan.framebuffers = result.vulkan.device.device.setupFramebuffers(
-    result.vulkan.swapchain,
-    result.vulkan.renderPass,
-    result.vulkan.frameSize
-  )
-  (
-    result.vulkan.device.commandPool,
-    result.vulkan.device.commandBuffers,
-  ) = result.vulkan.device.device.setupCommandBuffers(
-      result.vulkan.device.graphicsQueueFamily)
-
-  (
-    result.vulkan.imageAvailableSemaphores,
-    result.vulkan.renderFinishedSemaphores,
-    result.vulkan.inFlightFences,
-  ) = result.vulkan.device.device.setupSyncPrimitives()
-
-
-proc setupPipeline*[VertexType; UniformType; IndexType: uint16|uint32](engine: var Engine, scenedata: Thing, vertexShader, fragmentShader: static string): RenderPipeline[VertexType, UniformType] =
-  engine.currentscenedata = scenedata
-  result = initRenderPipeline[VertexType, UniformType](
-    engine.vulkan.device.device,
-    engine.vulkan.frameSize,
-    engine.vulkan.renderPass,
-    vertexShader,
-    fragmentShader,
-  )
-
-  for mesh in allPartsOfType[Mesh[VertexType, IndexType]](
-      engine.currentscenedata):
-    result.vertexBuffers.add createIndexedVertexBuffers(mesh,
-        result.device, engine.vulkan.device.physicalDevice.device,
-        engine.vulkan.device.commandPool, engine.vulkan.device.graphicsQueue)
-
-  # uniform buffers
-  when not (UniformType is void):
-    result.uniformBuffers = createUniformBuffers[MAX_FRAMES_IN_FLIGHT, UniformType](
-      result.device,
-      engine.vulkan.device.physicalDevice.device
-    )
-
-  var
-    poolSize = VkDescriptorPoolSize(
-      thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-      descriptorCount: uint32(MAX_FRAMES_IN_FLIGHT),
-    )
-    poolInfo = VkDescriptorPoolCreateInfo(
-      sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
-      poolSizeCount: 1,
-      pPoolSizes: addr(poolSize),
-      maxSets: uint32(MAX_FRAMES_IN_FLIGHT),
-    )
-  checkVkResult vkCreateDescriptorPool(result.device, addr(poolInfo), nil, addr(result.descriptorPool))
-
-  var layouts: array[MAX_FRAMES_IN_FLIGHT, VkDescriptorSetLayout]
-  for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
-    layouts[i] = result.descriptorSetLayout
-  var allocInfo = VkDescriptorSetAllocateInfo(
-    sType: VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
-    descriptorPool: result.descriptorPool,
-    descriptorSetCount: uint32(MAX_FRAMES_IN_FLIGHT),
-    pSetLayouts: addr(layouts[0]),
-  )
-
-  checkVkResult vkAllocateDescriptorSets(result.device, addr(allocInfo), addr(result.descriptors[0]))
-
-  when not (UniformType is void):
-    var bufferInfos: array[MAX_FRAMES_IN_FLIGHT, array[1, VkDescriptorBufferInfo]] # because we use only one Uniform atm
-    for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
-      bufferInfos[i][0] = VkDescriptorBufferInfo(
-        buffer: result.uniformBuffers[i].vkBuffer,
-        offset: VkDeviceSize(0),
-        range: VkDeviceSize(sizeof(UniformType)),
-      )
-      var descriptorWrite = VkWriteDescriptorSet(
-          sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
-          dstSet: result.descriptors[i],
-          dstBinding: 0,
-          dstArrayElement: 0,
-          descriptorType: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
-          descriptorCount: 1,
-          pBufferInfo: addr(bufferInfos[i][0]),
-        )
-      vkUpdateDescriptorSets(result.device, 1, addr(descriptorWrite), 0, nil)
-
-proc updateBufferData*[T](device: Device, buffer: Buffer, data: var T) =
-  when stripGenericParams(T) is seq: # seq needs special treatment for automated data uploading
-    assert data.len > 0
-    let size = data.len * sizeof(get(genericParams(typeof(data)), 0))
-    let dataptr = addr(data[0])
-  else:
-    let size = sizeof(data)
-    let dataptr = addr(data)
-  if not (HostVisible in buffer.memoryProperties):
-    if not (TransferDst in buffer.bufferTypes):
-      raise newException(Exception, "Buffer cannot be updated")
-    var stagingBuffer = device.device.InitBuffer(device.physicalDevice.device,
-        uint64(size), {TransferSrc}, {HostVisible, HostCoherent})
-    copyMem(stagingBuffer.data, dataptr, size)
-    transferBuffer(device.commandPool, device.graphicsQueue, stagingBuffer,
-        buffer, uint64(size))
-    stagingBuffer.trash()
-  else:
-    copyMem(buffer.data, dataptr, size)
-
-proc updateVertexData*[T: VertexAttribute](device: Device,
-    vertexAttribute: var T) =
-  device.updateBufferData(vertexAttribute.buffer, vertexAttribute.data)
-
-proc updateUniformData*[VertexType, Uniforms](device: Device,
-    pipeline: RenderPipeline[VertexType, Uniforms], data: var Uniforms) =
-  for buffer in pipeline.uniformBuffers:
-    device.updateBufferData(buffer, data)
-
-
-proc runPipeline[VertexType; Uniforms](commandBuffer: VkCommandBuffer, pipeline: var RenderPipeline[VertexType, Uniforms], currentFrame: int) =
-  vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline)
-  vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.layout, 0, 1, addr(pipeline.descriptors[currentFrame]), 0, nil)
-
-  for (vertexBufferSet, indexed, indexBuffer, count, indexType) in pipeline.vertexBuffers:
-    var
-      vertexBuffers: seq[VkBuffer]
-      offsets: seq[VkDeviceSize]
-    for buffer in vertexBufferSet:
-      vertexBuffers.add buffer.vkBuffer
-      offsets.add VkDeviceSize(0)
-
-    vkCmdBindVertexBuffers(commandBuffer, firstBinding = 0'u32, bindingCount = uint32(vertexBuffers.len), pBuffers = addr(vertexBuffers[ 0]), pOffsets = addr(offsets[0]))
-    if indexed:
-      vkCmdBindIndexBuffer(commandBuffer, indexBuffer.vkBuffer, VkDeviceSize(0), indexType)
-      vkCmdDrawIndexed(commandBuffer, count, 1, 0, 0, 0)
-    else:
-      vkCmdDraw(commandBuffer, vertexCount = count, instanceCount = 1, firstVertex = 0, firstInstance = 0)
-
-proc recordCommandBuffer(renderPass: VkRenderPass, pipeline: var RenderPipeline,
-    commandBuffer: VkCommandBuffer, framebuffer: VkFramebuffer,
-    frameSize: TVec2[uint32], currentFrame: int) =
-  var
-    beginInfo = VkCommandBufferBeginInfo(
-      sType: VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
-      pInheritanceInfo: nil,
-    )
-    clearColor = VkClearValue(color: VkClearColorValue(float32: pipeline.clearColor))
-    renderPassInfo = VkRenderPassBeginInfo(
-      sType: VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
-      renderPass: renderPass,
-      framebuffer: framebuffer,
-      renderArea: VkRect2D(
-        offset: VkOffset2D(x: 0, y: 0),
-        extent: VkExtent2D(width: frameSize.x, height: frameSize.y),
-      ),
-      clearValueCount: 1,
-      pClearValues: addr(clearColor),
-    )
-    viewport = VkViewport(
-      x: 0.0,
-      y: 0.0,
-      width: (float)frameSize.x,
-      height: (float)frameSize.y,
-      minDepth: 0.0,
-      maxDepth: 1.0,
-    )
-    scissor = VkRect2D(
-      offset: VkOffset2D(x: 0, y: 0),
-      extent: VkExtent2D(width: frameSize.x, height: frameSize.y)
-    )
-  checkVkResult vkBeginCommandBuffer(commandBuffer, addr(beginInfo))
-  block:
-    vkCmdBeginRenderPass(commandBuffer, addr(renderPassInfo), VK_SUBPASS_CONTENTS_INLINE)
-    vkCmdSetViewport(commandBuffer, firstViewport = 0, viewportCount = 1, addr(viewport))
-    vkCmdSetScissor(commandBuffer, firstScissor = 0, scissorCount = 1, addr(scissor))
-    runPipeline(commandBuffer, pipeline, currentFrame)
-    vkCmdEndRenderPass(commandBuffer)
-  checkVkResult vkEndCommandBuffer(commandBuffer)
-
-proc drawFrame(window: NativeWindow, vulkan: var Vulkan, currentFrame: int, resized: bool, pipeline: var RenderPipeline) =
-
-  checkVkResult vkWaitForFences(vulkan.device.device, 1, addr(vulkan.inFlightFences[currentFrame]), VK_TRUE, high(uint64))
-
-  var bufferImageIndex: uint32
-  let nextImageResult = vkAcquireNextImageKHR(
-    vulkan.device.device,
-    vulkan.swapchain.swapchain,
-    high(uint64),
-    vulkan.imageAvailableSemaphores[currentFrame],
-    VkFence(0),
-    addr(bufferImageIndex)
-  )
-  if nextImageResult == VK_ERROR_OUT_OF_DATE_KHR:
-    vulkan.frameSize = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface)
-    (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
-  elif not (nextImageResult in [VK_SUCCESS, VK_SUBOPTIMAL_KHR]):
-    raise newException(Exception, "Vulkan error: vkAcquireNextImageKHR returned " & $nextImageResult)
-  checkVkResult vkResetFences(vulkan.device.device, 1, addr(vulkan.inFlightFences[currentFrame]))
-
-  checkVkResult vkResetCommandBuffer(vulkan.device.commandBuffers[currentFrame], VkCommandBufferResetFlags(0))
-  vulkan.renderPass.recordCommandBuffer(
-    pipeline,
-    vulkan.device.commandBuffers[currentFrame],
-    vulkan.framebuffers[bufferImageIndex], vulkan.frameSize,
-    currentFrame
-  )
-  var
-    waitSemaphores = [vulkan.imageAvailableSemaphores[currentFrame]]
-    waitStages = [VkPipelineStageFlags(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)]
-    signalSemaphores = [vulkan.renderFinishedSemaphores[currentFrame]]
-    submitInfo = VkSubmitInfo(
-      sType: VK_STRUCTURE_TYPE_SUBMIT_INFO,
-      waitSemaphoreCount: 1,
-      pWaitSemaphores: addr(waitSemaphores[0]),
-      pWaitDstStageMask: addr(waitStages[0]),
-      commandBufferCount: 1,
-      pCommandBuffers: addr(vulkan.device.commandBuffers[currentFrame]),
-      signalSemaphoreCount: 1,
-      pSignalSemaphores: addr(signalSemaphores[0]),
-    )
-  checkVkResult vkQueueSubmit(vulkan.device.graphicsQueue, 1, addr(submitInfo), vulkan.inFlightFences[currentFrame])
-
-  var presentInfo = VkPresentInfoKHR(
-    sType: VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
-    waitSemaphoreCount: 1,
-    pWaitSemaphores: addr(signalSemaphores[0]),
-    swapchainCount: 1,
-    pSwapchains: addr(vulkan.swapchain.swapchain),
-    pImageIndices: addr(bufferImageIndex),
-    pResults: nil,
-  )
-  let presentResult = vkQueuePresentKHR(vulkan.device.presentationQueue, addr(presentInfo))
-  if presentResult == VK_ERROR_OUT_OF_DATE_KHR or presentResult == VK_SUBOPTIMAL_KHR or resized:
-    vulkan.frameSize = window.getFrameDimension(vulkan.device.physicalDevice.device, vulkan.surface)
-    (vulkan.swapchain, vulkan.framebuffers) = vulkan.recreateSwapchain()
-
-
-func frametime(engine: Engine): auto =
-  if engine.maxFPS == 0: 0'f
-  else: 1'f / float32(engine.maxFPS)
-
-proc run*(engine: var Engine, pipeline: var RenderPipeline, globalUpdate: proc(
-    engine: var Engine, t, dt: float32)) =
-  var
-    currentFrame = 0
-    resized = false
-    lastUpdate = cpuTime()
-    lastframe = 0'f
-
-  while true:
-    # process input
-    engine.input.keysPressed = {}
-    engine.input.keysReleased = {}
-    engine.input.mousePressed = {}
-    engine.input.mouseReleased = {}
-    var killed = false
-    for event in engine.window.pendingEvents():
-      case event.eventType:
-        of Quit:
-          killed = true
-        of ResizedWindow:
-          resized = true
-        of KeyPressed:
-          engine.input.keysPressed.incl event.key
-          engine.input.keysDown.incl event.key
-        of KeyReleased:
-          engine.input.keysReleased.incl event.key
-          engine.input.keysDown.excl event.key
-        of MousePressed:
-          engine.input.mousePressed.incl event.button
-          engine.input.mouseDown.incl event.button
-        of MouseReleased:
-          engine.input.mouseReleased.incl event.button
-          engine.input.mouseDown.excl event.button
-        of MouseMoved:
-          engine.input.mousePos = Vec2([float32(event.x), float32(event.y)])
-    if killed: # at least on windows we should return immediately as swapchain recreation will fail after kill
-      break
-
-    # game logic update
-    let
-      now = cpuTime()
-      dt = now - lastUpdate
-    lastUpdate = now
-    engine.globalUpdate(now, dt)
-    for thing in allThings(engine.currentscenedata):
-      for part in thing.parts:
-        update(part, engine, now, dt)
-      update(thing, engine, now, dt)
-
-    # submit frame for drawing
-    if engine.maxFPS == 0 or (now - lastframe >= engine.frametime): # framerate limit
-      engine.window.drawFrame(engine.vulkan, currentFrame, resized, pipeline)
-      lastframe = now
-      currentFrame = (currentFrame + 1) mod MAX_FRAMES_IN_FLIGHT
-    resized = false
-
-  checkVkResult vkDeviceWaitIdle(engine.vulkan.device.device)
-
-proc trash*(pipeline: var RenderPipeline) =
-  vkDestroyDescriptorPool(pipeline.device, pipeline.descriptorPool, nil)
-  vkDestroyDescriptorSetLayout(pipeline.device, pipeline.descriptorSetLayout, nil)
-  vkDestroyPipeline(pipeline.device, pipeline.pipeline, nil)
-  vkDestroyPipelineLayout(pipeline.device, pipeline.layout, nil)
-  for shader in pipeline.shaders:
-    vkDestroyShaderModule(pipeline.device, shader.shader.module, nil)
-
-  for (bufferset, indexed, indexbuffer, cnt, t) in
-    pipeline.vertexBuffers.mitems:
-    if indexed:
-      indexbuffer.trash()
-    for buffer in bufferset.mitems:
-      buffer.trash()
-  for buffer in pipeline.uniformBuffers.mitems:
-    buffer.trash()
-
-proc trash*(engine: var Engine) =
-  checkVkResult vkDeviceWaitIdle(engine.vulkan.device.device)
-  engine.vulkan.device.device.trash(engine.vulkan.swapchain,
-      engine.vulkan.framebuffers)
-
-  for i in 0 ..< MAX_FRAMES_IN_FLIGHT:
-    engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.imageAvailableSemaphores[i], nil)
-    engine.vulkan.device.device.vkDestroySemaphore(engine.vulkan.renderFinishedSemaphores[i], nil)
-    engine.vulkan.device.device.vkDestroyFence(engine.vulkan.inFlightFences[i], nil)
-
-  engine.vulkan.device.device.vkDestroyRenderPass(engine.vulkan.renderPass, nil)
-  engine.vulkan.device.device.vkDestroyCommandPool(engine.vulkan.device.commandPool, nil)
-
-  engine.vulkan.instance.vkDestroySurfaceKHR(engine.vulkan.surface, nil)
-  engine.vulkan.device.device.vkDestroyDevice(nil)
-  when DEBUG_LOG:
-    engine.vulkan.instance.vkDestroyDebugUtilsMessengerEXT(engine.vulkan.debugMessenger, nil)
-  engine.window.trash()
-  # needs to happen after window is trashed as the driver might have a hook registered for the window destruction
-  engine.vulkan.instance.vkDestroyInstance(nil)
--- a/src/semicongine/legacy/glsl.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-import std/typetraits
-import std/strformat
-import ../math/vector
-import ../math/matrix
-
-
-func getGLSLType*[T](t: T): string {.compileTime.} =
-  # todo: likely not correct as we would need to enable some 
-  # extensions somewhere (Vulkan/GLSL compiler?) to have 
-  # everything work as intended. Or maybe the GPU driver does
-  # some automagic conversion stuf..
-  when T is uint8:         "uint"
-  elif T is int8:          "int"
-  elif T is uint16:        "uint"
-  elif T is int16:         "int"
-  elif T is uint32:        "uint"
-  elif T is int32:         "int"
-  elif T is uint64:        "uint"
-  elif T is int64:         "int"
-  elif T is float32:       "float"
-  elif T is float64:       "double"
-
-  elif T is TVec2[uint8]:   "uvec2"
-  elif T is TVec2[int8]:    "ivec2"
-  elif T is TVec2[uint16]:  "uvec2"
-  elif T is TVec2[int16]:   "ivec2"
-  elif T is TVec2[uint32]:  "uvec2"
-  elif T is TVec2[int32]:   "ivec2"
-  elif T is TVec2[uint64]:  "uvec2"
-  elif T is TVec2[int64]:   "ivec2"
-  elif T is TVec2[float32]: "vec2"
-  elif T is TVec2[float64]: "dvec2"
-
-  elif T is TVec3[uint8]:   "uvec3"
-  elif T is TVec3[int8]:    "ivec3"
-  elif T is TVec3[uint16]:  "uvec3"
-  elif T is TVec3[int16]:   "ivec3"
-  elif T is TVec3[uint32]:  "uvec3"
-  elif T is TVec3[int32]:   "ivec3"
-  elif T is TVec3[uint64]:  "uvec3"
-  elif T is TVec3[int64]:   "ivec3"
-  elif T is TVec3[float32]: "vec3"
-  elif T is TVec3[float64]: "dvec3"
-
-  elif T is TVec4[uint8]:   "uvec4"
-  elif T is TVec4[int8]:    "ivec4"
-  elif T is TVec4[uint16]:  "uvec4"
-  elif T is TVec4[int16]:   "ivec4"
-  elif T is TVec4[uint32]:  "uvec4"
-  elif T is TVec4[int32]:   "ivec4"
-  elif T is TVec4[uint64]:  "uvec4"
-  elif T is TVec4[int64]:   "ivec4"
-  elif T is TVec4[float32]: "vec4"
-  elif T is TVec4[float64]: "dvec4"
-
-  elif T is TMat22[float32]: "mat2"
-  elif T is TMat23[float32]: "mat32"
-  elif T is TMat32[float32]: "mat23"
-  elif T is TMat33[float32]: "mat3"
-  elif T is TMat34[float32]: "mat43"
-  elif T is TMat43[float32]: "mat34"
-  elif T is TMat44[float32]: "mat4"
-
-  elif T is TMat22[float64]: "dmat2"
-  elif T is TMat23[float64]: "dmat32"
-  elif T is TMat32[float64]: "dmat23"
-  elif T is TMat33[float64]: "dmat3"
-  elif T is TMat34[float64]: "dmat43"
-  elif T is TMat43[float64]: "dmat34"
-  elif T is TMat44[float64]: "dmat4"
-
-
-# return the number of elements into which larger types are divided
-func compositeAttributesNumber*[T](value: T): int =
-  when T is TMat33[float32]:
-    3
-  elif T is TMat44[float32]:
-    4
-  else:
-    1
-
-
-# from https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html
-func nLocationSlots*[T](value: T): uint32 =
-  when (T is TVec3[float64] or T is TVec3[uint64] or T is TVec4[float64] or T is TVec4[float64]):
-    return 2
-  elif T is SomeNumber or T is TVec:
-    return 1
-  else:
-    raise newException(Exception, "Unsupported vertex attribute type")
-
-
-# return the type into which larger types are divided
-func compositeAttribute*[T](value: T): auto =
-  when T is TMat33[float32]:
-    Vec3()
-  elif T is TMat44[float32]:
-    Vec4()
-  else:
-    value
-
-func glslInput*[T](): seq[string] {.compileTime.} =
-  when not (T is void):
-    var i = 0'u32
-    for fieldname, value in default(T).fieldPairs:
-      let glsltype = getGLSLType(value)
-      let thename = fieldname
-      result.add &"layout(location = {i}) in {glsltype} {thename};"
-      for j in 0 ..< compositeAttributesNumber(value):
-        i += nLocationSlots(compositeAttribute(value))
-
-func glslUniforms*[T](): seq[string] {.compileTime.} =
-  # currently only a single uniform block supported, therefore binding = 0
-  when not (T is void):
-    let uniformName = name(T)
-    result.add(&"layout(binding = 0) uniform T{uniformName} {{")
-    for fieldname, value in default(T).fieldPairs:
-      let glsltype = getGLSLType(value)
-      let thename = fieldname
-      result.add(&"    {glsltype} {thename};")
-    result.add(&"}} {uniformName};")
-
-func glslOutput*[T](): seq[string] {.compileTime.} =
-  when not (T is void):
-    var i = 0'u32
-    for fieldname, value in default(T).fieldPairs:
-      let glsltype = getGLSLType(value)
-      let thename = fieldname
-      result.add &"layout(location = {i}) out {glsltype} {thename};"
-      i += 1
-  else:
-    result
--- a/src/semicongine/legacy/glsl_helpers.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-import ./math/vector
-import ./math/matrix
-
-func getGLSLType*[T](): string =
-  # todo: likely not correct as we would need to enable some 
-  # extensions somewhere (Vulkan/GLSL compiler?) to have 
-  # everything work as intended. Or maybe the GPU driver does
-  # some automagic conversion stuf..
-  when T is uint8:         "uint"
-  elif T is int8:          "int"
-  elif T is uint16:        "uint"
-  elif T is int16:         "int"
-  elif T is uint32:        "uint"
-  elif T is int32:         "int"
-  elif T is uint64:        "uint"
-  elif T is int64:         "int"
-  elif T is float32:       "float"
-  elif T is float64:       "double"
-
-  elif T is TVec2[uint8]:   "uvec2"
-  elif T is TVec2[int8]:    "ivec2"
-  elif T is TVec2[uint16]:  "uvec2"
-  elif T is TVec2[int16]:   "ivec2"
-  elif T is TVec2[uint32]:  "uvec2"
-  elif T is TVec2[int32]:   "ivec2"
-  elif T is TVec2[uint64]:  "uvec2"
-  elif T is TVec2[int64]:   "ivec2"
-  elif T is TVec2[float32]: "vec2"
-  elif T is TVec2[float64]: "dvec2"
-
-  elif T is TVec3[uint8]:   "uvec3"
-  elif T is TVec3[int8]:    "ivec3"
-  elif T is TVec3[uint16]:  "uvec3"
-  elif T is TVec3[int16]:   "ivec3"
-  elif T is TVec3[uint32]:  "uvec3"
-  elif T is TVec3[int32]:   "ivec3"
-  elif T is TVec3[uint64]:  "uvec3"
-  elif T is TVec3[int64]:   "ivec3"
-  elif T is TVec3[float32]: "vec3"
-  elif T is TVec3[float64]: "dvec3"
-
-  elif T is TVec4[uint8]:   "uvec4"
-  elif T is TVec4[int8]:    "ivec4"
-  elif T is TVec4[uint16]:  "uvec4"
-  elif T is TVec4[int16]:   "ivec4"
-  elif T is TVec4[uint32]:  "uvec4"
-  elif T is TVec4[int32]:   "ivec4"
-  elif T is TVec4[uint64]:  "uvec4"
-  elif T is TVec4[int64]:   "ivec4"
-  elif T is TVec4[float32]: "vec4"
-  elif T is TVec4[float64]: "dvec4"
-
-  elif T is TMat22[float32]: "mat2"
-  elif T is TMat23[float32]: "mat32"
-  elif T is TMat32[float32]: "mat23"
-  elif T is TMat33[float32]: "mat3"
-  elif T is TMat34[float32]: "mat43"
-  elif T is TMat43[float32]: "mat34"
-  elif T is TMat44[float32]: "mat4"
-
-  elif T is TMat22[float64]: "dmat2"
-  elif T is TMat23[float64]: "dmat32"
-  elif T is TMat32[float64]: "dmat23"
-  elif T is TMat33[float64]: "dmat3"
-  elif T is TMat34[float64]: "dmat43"
-  elif T is TMat43[float64]: "dmat34"
-  elif T is TMat44[float64]: "dmat4"
--- a/src/semicongine/legacy/image.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-import ./buffer
-import ./math/vector
-import ./vulkan
-import ./vulkan_helpers
-
-type
-  ImageUsage* = enum
-    TransferDst = VK_IMAGE_USAGE_TRANSFER_DST_BIT
-    SampledBit = VK_IMAGE_USAGE_SAMPLED_BIT
-  ImageUsages = set[ImageUsage]
-  Image = object
-    buffer: Buffer
-    image: VkImage
-    memory: VkDeviceMemory
-
-proc InitImage(data: var seq[byte], size: TVec2[uint32], format: VkFormat,
-    tiling: VkImageTiling, usage: ImageUsages, properties: MemoryProperties,
-        device: VkDevice,
-    physicalDevice: VkPhysicalDevice): Image =
-  result.buffer = InitBuffer(device, physicalDevice, uint64(data.len), {
-      TransferSrc}, {HostVisible, HostCoherent})
-  copyMem(result.buffer.data, addr(data[0]), data.len)
-
-  var imageInfo = VkImageCreateInfo(
-    sType: VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
-    imageType: VK_IMAGE_TYPE_2D,
-    extent: VkExtent3D(width: size.x, height: size.y, depth: 1),
-    mipLevels: 1,
-    arrayLayers: 1,
-    format: format,
-    tiling: tiling,
-    initialLayout: VK_IMAGE_LAYOUT_UNDEFINED,
-    usage: cast[VkImageUsageFlags](usage),
-    sharingMode: VK_SHARING_MODE_EXCLUSIVE,
-    samples: VK_SAMPLE_COUNT_1_BIT,
-  )
-  checkVkResult vkCreateImage(device, addr(imageInfo), nil, addr(result.image))
-
-  var memRequirements: VkMemoryRequirements
-  vkGetImageMemoryRequirements(device, result.image, addr(memRequirements))
-
-  var allocInfo = VkMemoryAllocateInfo(
-    sType: VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
-    allocationSize: memRequirements.size,
-    memoryTypeIndex: memRequirements.findMemoryType(physicalDevice, properties)
-  )
-
-  checkVkResult vkAllocateMemory(device, addr(allocInfo), nil, addr(result.memory))
-  checkVkResult vkBindImageMemory(device, result.image, result.memory,
-      VkDeviceSize(0))
--- a/src/semicongine/legacy/shader.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-import std/os
-import std/typetraits
-import std/hashes
-import std/strformat
-import std/strutils
-import std/tables
-import std/compilesettings
-
-import ./vulkan_helpers
-import ./glsl_helpers
-import ./vulkan
-import ./vertex
-import ./descriptor
-import ./math/vector
-
-type
-  AllowedUniformType = SomeNumber|TVec
-  UniformSlot *[T: AllowedUniformType] = object
-  ShaderProgram*[VertexType, Uniforms] = object
-    entryPoint*: string
-    programType*: VkShaderStageFlagBits
-    shader*: VkPipelineShaderStageCreateInfo
-    uniforms*: Uniforms
-
-proc staticExecChecked(command: string, input = ""): string {.compileTime.} =
-  let (output, exitcode) = gorgeEx(
-      command = command,
-      input = input)
-  if exitcode != 0:
-    raise newException(Exception, &"Running '{command}' produced exit code: {exitcode}" & output)
-  return output
-
-
-func stage2string(stage: VkShaderStageFlagBits): string {.compileTime.} =
-  case stage
-  of VK_SHADER_STAGE_VERTEX_BIT: "vert"
-  of VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: "tesc"
-  of VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: "tese"
-  of VK_SHADER_STAGE_GEOMETRY_BIT: "geom"
-  of VK_SHADER_STAGE_FRAGMENT_BIT: "frag"
-  of VK_SHADER_STAGE_COMPUTE_BIT: "comp"
-  else: ""
-
-proc compileGLSLToSPIRV(stage: static VkShaderStageFlagBits, shaderSource: static string, entrypoint: string): seq[uint32] {.compileTime.} =
-  when defined(nimcheck): # will not run if nimcheck is running
-    return result
-  const
-    stagename = stage2string(stage)
-    shaderHash = hash(shaderSource)
-    # cross compilation for windows workaround, sorry computer
-    shaderfile = getTempDir() / fmt"shader_{shaderHash}.{stagename}"
-    projectPath = querySetting(projectPath)
-
-  discard staticExecChecked(
-      command = fmt"{projectPath}/glslangValidator --entry-point {entrypoint} -V --stdin -S {stagename} -o {shaderfile}",
-      input = shaderSource
-  )
-
-  when defined(mingw) and defined(linux): # required for crosscompilation, path separators get messed up
-    let shaderbinary = staticRead shaderfile.replace("\\", "/")
-  else:
-    let shaderbinary = staticRead shaderfile
-  when defined(linux):
-    discard staticExecChecked(command = fmt"rm {shaderfile}")
-  elif defined(windows):
-    discard staticExecChecked(command = fmt"cmd.exe /c del {shaderfile}")
-  else:
-    raise newException(Exception, "Unsupported operating system")
-
-  var i = 0
-  while i < shaderbinary.len:
-    result.add(
-      (uint32(shaderbinary[i + 0]) shl 0) or
-      (uint32(shaderbinary[i + 1]) shl 8) or
-      (uint32(shaderbinary[i + 2]) shl 16) or
-      (uint32(shaderbinary[i + 3]) shl 24)
-    )
-    i += 4
-
-proc initShaderProgram*[VertexType, Uniforms](device: VkDevice, programType: static VkShaderStageFlagBits, shader: static string, entryPoint: static string = "main"): ShaderProgram[VertexType, Uniforms] =
-  result.entryPoint = entryPoint
-  result.programType = programType
-
-  const constcode = compileGLSLToSPIRV(programType, shader, entryPoint)
-  var code = constcode
-  var createInfo = VkShaderModuleCreateInfo(
-    sType: VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
-    codeSize: uint(code.len * sizeof(uint32)),
-    pCode: if code.len > 0: addr(code[0]) else: nil,
-  )
-  var shaderModule: VkShaderModule
-  checkVkResult vkCreateShaderModule(device, addr(createInfo), nil, addr(shaderModule))
-
-  result.shader = VkPipelineShaderStageCreateInfo(
-    sType: VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
-    stage: programType,
-    module: shaderModule,
-    pName: cstring(result.entryPoint), # entry point for shader
-  )
-
-func generateVertexShaderCode*[VertexType, Uniforms](
-  shaderBody: static string = "",
-  entryPoint: static string = "main",
-  glslVersion: static string = "450"
-): string {.compileTime.} =
-  var lines: seq[string]
-  lines.add "#version " & glslVersion
-  lines.add "layout(row_major) uniform;"
-  lines.add generateGLSLUniformDeclarations[Uniforms]()
-  lines.add generateGLSLVertexDeclarations[VertexType]()
-  lines.add "layout(location = 0) out vec4 fragColor;"
-  lines.add "void " & entryPoint & "() {"
-
-  var viewprojection = ""
-
-  var hasPosition = 0
-  var hasColor = 0
-  for attrname, value in VertexType().fieldPairs:
-    when typeof(value) is PositionAttribute:
-      let glsltype = getGLSLType[getAttributeType(value)]()
-      lines.add &"    {glsltype} in_position = " & attrname & ";"
-      if getAttributeType(value) is TVec2:
-        lines.add "    vec4 out_position = vec4(in_position, 0.0, 1.0);"
-      elif getAttributeType(value) is TVec3:
-        lines.add "    vec4 out_position = vec4(in_position, 1.0);"
-      elif getAttributeType(value) is TVec4:
-        lines.add "    vec4 out_position = in_position;"
-      hasPosition += 1
-    when typeof(value) is ModelTransformAttribute:
-      lines.add &"    out_position = " & attrname & " * out_position;"
-    when typeof(value) is ColorAttribute:
-      let glsltype = getGLSLType[getAttributeType(value)]()
-      lines.add &"    {glsltype} in_color = " & attrname & ";"
-      if getAttributeType(value) is TVec3:
-        lines.add &"    vec4 out_color = vec4(in_color, 1);";
-      elif getAttributeType(value) is TVec4:
-        lines.add &"    vec4 out_color = in_color;";
-      hasColor += 1
-  when not (Uniforms is void):
-    let uniformBlockName = name(Uniforms).toLower()
-    for attrname, value in Uniforms().fieldPairs:
-      when typeof(value) is ViewProjectionTransform:
-        lines.add "out_position = " & uniformBlockName & "." & attrname & " * out_position;"
-
-  lines.add shaderBody
-  lines.add "    gl_Position = out_position;"
-  lines.add "    fragColor = out_color;"
-  lines.add "}"
-  if hasPosition != 1:
-    raise newException(Exception, fmt"VertexType needs to have exactly one attribute of type PositionAttribute (has {hasPosition})")
-  if hasColor != 1:
-    raise newException(Exception, fmt"VertexType needs to have exactly one attribute of type ColorAttribute (has {hasColor})")
-  return lines.join("\n")
-
-func generateFragmentShaderCode*[VertexType](
-  shaderBody: static string = "",
-  entryPoint: static string = "main",
-  glslVersion: static string = "450"
-): string {.compileTime.} =
-  var lines: seq[string]
-  lines.add "#version " & glslVersion
-  lines.add "layout(row_major) uniform;"
-  lines.add "layout(location = 0) in vec4 fragColor;"
-  lines.add "layout(location = 0) out vec4 outColor;"
-  lines.add "void " & entryPoint & "() {"
-  lines.add "    vec4 in_color = fragColor;"
-  lines.add "    vec4 out_color = in_color;"
-  lines.add shaderBody
-  lines.add "    outColor = out_color;"
-  lines.add "}"
-
-  return lines.join("\n")
--- a/src/semicongine/legacy/thing.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-import std/strformat
-import std/typetraits
-
-import ./math/matrix
-
-type
-  Part* = ref object of RootObj
-    thing*: Thing
-
-  Thing* = ref object of RootObj
-    name*: string
-    transform*: Mat44 # todo: cache transform + only update VBO when transform changed
-    parent*: Thing
-    children*: seq[Thing]
-    parts*: seq[Part]
-
-
-func `$`*(thing: Thing): string = thing.name
-method `$`*(part: Part): string {.base.} =
-  if part.thing != nil:
-    &"{part.thing} -> Part"
-  else:
-    &"Standalone Part"
-
-proc add*(thing: Thing, child: Thing) =
-  child.parent = thing
-  thing.children.add child
-proc add*(thing: Thing, part: Part) =
-  part.thing = thing
-  thing.parts.add part
-proc add*(thing: Thing, children: seq[Thing]) =
-  for child in children:
-    child.parent = thing
-    thing.children.add child
-proc add*(thing: Thing, parts: seq[Part]) =
-  for part in parts:
-    part.thing = thing
-    thing.parts.add part
-
-func newThing*(name: string = ""): Thing =
-  result = new Thing
-  result.name = name
-  result.transform = Unit44
-  if result.name == "":
-    result.name = &"Thing[{$(cast[ByteAddress](result))}]"
-
-func newThing*(name: string, firstChild: Thing, children: varargs[
-    Thing]): Thing =
-  result = new Thing
-  result.add firstChild
-  for child in children:
-    result.add child
-  result.name = name
-  result.transform = Unit44
-  if result.name == "":
-    result.name = &"Thing[{$(cast[ByteAddress](result))}]"
-
-proc newThing*(name: string, firstPart: Part, parts: varargs[Part]): Thing =
-  result = new Thing
-  result.name = name
-  result.add firstPart
-  for part in parts:
-    result.add part
-  if result.name == "":
-    result.name = &"Thing[{$(cast[ByteAddress](result))}]"
-  result.transform = Unit44
-
-func getModelTransform*(thing: Thing): Mat44 =
-  result = Unit44
-  var currentThing = thing
-  while currentThing != nil:
-    result = currentThing.transform * result
-    currentThing = currentThing.parent
-
-iterator allPartsOfType*[T: Part](root: Thing): T =
-  var queue = @[root]
-  while queue.len > 0:
-    let thing = queue.pop
-    for part in thing.parts:
-      if part of T:
-        yield T(part)
-    for i in countdown(thing.children.len - 1, 0):
-      queue.add thing.children[i]
-
-func firstWithName*(root: Thing, name: string): Thing =
-  var queue = @[root]
-  while queue.len > 0:
-    let next = queue.pop
-    for child in next.children:
-      if child.name == name:
-        return child
-      queue.add child
-
-func firstPartWithName*[T: Part](root: Thing, name: string): T =
-  var queue = @[root]
-  while queue.len > 0:
-    let next = queue.pop
-    for child in next.children:
-      if child.name == name:
-        for part in child.parts:
-          if part of T:
-            return T(part)
-      queue.add child
-
-func allWithName*(root: Thing, name: string): seq[Thing] =
-  var queue = @[root]
-  while queue.len > 0:
-    let next = queue.pop
-    for child in next.children:
-      if child.name == name:
-        result.add child
-      queue.add child
-
-func allPartsWithName*[T: Part](root: Thing, name: string): seq[T] =
-  var queue = @[root]
-  while queue.len > 0:
-    let next = queue.pop
-    for child in next.children:
-      if child.name == name:
-        for part in child.parts:
-          if part of T:
-            result.add T(part)
-      queue.add child
-
-iterator allThings*(root: Thing): Thing =
-  var queue = @[root]
-  while queue.len > 0:
-    let next = queue.pop
-    for child in next.children:
-      queue.add child
-    yield next
--- a/src/semicongine/legacy/vertex.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-import std/options
-import std/macros
-import std/strutils
-import std/strformat
-import std/typetraits
-
-import ./math/vector
-import ./math/matrix
-import ./vulkan
-import ./buffer
-import ./glsl_helpers
-
-type
-  VertexAttributeType = SomeNumber|TVec|TMat
-  # useOnDeviceMemory can be used to make sure the attribute buffer memory will
-  # be on the device. Data will be faster to access but much slower to update
-  GenericAttribute*[T: VertexAttributeType] = object
-    data*: seq[T]
-    buffer*: Buffer
-    useOnDeviceMemory*: bool
-  PositionAttribute*[T: TVec] = object
-    data*: seq[T]
-    buffer*: Buffer
-    useOnDeviceMemory*: bool
-  ColorAttribute*[T: TVec] = object
-    data*: seq[T]
-    buffer*: Buffer
-    useOnDeviceMemory*: bool
-  GenericInstanceAttribute*[T: VertexAttributeType] = object
-    data*: seq[T]
-    buffer*: Buffer
-    useOnDeviceMemory*: bool
-  ModelTransformAttribute* = GenericInstanceAttribute[Mat44]
-  InstanceAttribute* = GenericInstanceAttribute|ModelTransformAttribute
-  VertexAttribute* = GenericAttribute|PositionAttribute|ColorAttribute|InstanceAttribute
-
-template getAttributeType*(v: VertexAttribute): auto = get(genericParams(typeof(v)), 0)
-
-func datasize*(attribute: VertexAttribute): uint64 =
-  uint64(sizeof(getAttributeType(attribute))) * uint64(attribute.data.len)
-
-# from https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html
-func nLocationSlots[T: VertexAttributeType](): int =
-  when (T is TVec3[float64] or T is TVec3[uint64] or T is TVec4[float64] or
-      T is TVec4[float64]):
-    2
-  elif T is SomeNumber or T is TVec:
-    1
-  else:
-    {.error: "Unsupported vertex attribute type".}
-
-# numbers
-func getVkFormat[T: VertexAttributeType](): VkFormat =
-  when T is uint8: VK_FORMAT_R8_UINT
-  elif T is int8: VK_FORMAT_R8_SINT
-  elif T is uint16: VK_FORMAT_R16_UINT
-  elif T is int16: VK_FORMAT_R16_SINT
-  elif T is uint32: VK_FORMAT_R32_UINT
-  elif T is int32: VK_FORMAT_R32_SINT
-  elif T is uint64: VK_FORMAT_R64_UINT
-  elif T is int64: VK_FORMAT_R64_SINT
-  elif T is float32: VK_FORMAT_R32_SFLOAT
-  elif T is float64: VK_FORMAT_R64_SFLOAT
-  elif T is TVec2[uint8]: VK_FORMAT_R8G8_UINT
-  elif T is TVec2[int8]: VK_FORMAT_R8G8_SINT
-  elif T is TVec2[uint16]: VK_FORMAT_R16G16_UINT
-  elif T is TVec2[int16]: VK_FORMAT_R16G16_SINT
-  elif T is TVec2[uint32]: VK_FORMAT_R32G32_UINT
-  elif T is TVec2[int32]: VK_FORMAT_R32G32_SINT
-  elif T is TVec2[uint64]: VK_FORMAT_R64G64_UINT
-  elif T is TVec2[int64]: VK_FORMAT_R64G64_SINT
-  elif T is TVec2[float32]: VK_FORMAT_R32G32_SFLOAT
-  elif T is TVec2[float64]: VK_FORMAT_R64G64_SFLOAT
-  elif T is TVec3[uint8]: VK_FORMAT_R8G8B8_UINT
-  elif T is TVec3[int8]: VK_FORMAT_R8G8B8_SINT
-  elif T is TVec3[uint16]: VK_FORMAT_R16G16B16_UINT
-  elif T is TVec3[int16]: VK_FORMAT_R16G16B16_SINT
-  elif T is TVec3[uint32]: VK_FORMAT_R32G32B32_UINT
-  elif T is TVec3[int32]: VK_FORMAT_R32G32B32_SINT
-  elif T is TVec3[uint64]: VK_FORMAT_R64G64B64_UINT
-  elif T is TVec3[int64]: VK_FORMAT_R64G64B64_SINT
-  elif T is TVec3[float32]: VK_FORMAT_R32G32B32_SFLOAT
-  elif T is TVec3[float64]: VK_FORMAT_R64G64B64_SFLOAT
-  elif T is TVec4[uint8]: VK_FORMAT_R8G8B8A8_UINT
-  elif T is TVec4[int8]: VK_FORMAT_R8G8B8A8_SINT
-  elif T is TVec4[uint16]: VK_FORMAT_R16G16B16A16_UINT
-  elif T is TVec4[int16]: VK_FORMAT_R16G16B16A16_SINT
-  elif T is TVec4[uint32]: VK_FORMAT_R32G32B32A32_UINT
-  elif T is TVec4[int32]: VK_FORMAT_R32G32B32A32_SINT
-  elif T is TVec4[uint64]: VK_FORMAT_R64G64B64A64_UINT
-  elif T is TVec4[int64]: VK_FORMAT_R64G64B64A64_SINT
-  elif T is TVec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT
-  elif T is TVec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT
-  else: {.error: "Unsupported vertex attribute type".}
-
-
-func VertexCount*[T](t: T): uint32 =
-  for name, value in t.fieldPairs:
-    when typeof(value) is VertexAttribute and not (typeof(
-        value) is InstanceAttribute):
-      if result == 0:
-        result = uint32(value.data.len)
-      else:
-        assert result == uint32(value.data.len)
-
-
-func hasAttributeType*[T, AT](t: T): uint32 =
-  for name, value in t.fieldPairs:
-    when typeof(value) is AT:
-      return true
-  return false
-
-# helper function to make sure matrices are correctly
-# divided into multiple vector attributes
-template compositeAttributeType[T]() =
-  when T is TMat33[float32]:
-    Vec3
-  elif T is TMat44[float32]:
-    Vec4
-  else:
-    T
-func compositeAttributesNumber[T](): int =
-  when T is TMat33[float32]:
-    3
-  elif T is TMat44[float32]:
-    4
-  else:
-    1
-
-
-func generateGLSLVertexDeclarations*[T](): string =
-  var stmtList: seq[string]
-  var i = 0
-  for name, value in T().fieldPairs:
-    when typeof(value) is VertexAttribute:
-      let glsltype = getGLSLType[getAttributeType(value)]()
-      let n = name
-      stmtList.add(&"layout(location = {i}) in {glsltype} {n};")
-      for j in 0 ..< compositeAttributesNumber[getAttributeType(value)]():
-        i += nLocationSlots[compositeAttributeType(getAttributeType(value))]()
-
-  return stmtList.join("\n")
-
-
-func generateInputVertexBinding*[T](bindingoffset: int = 0, locationoffset: int = 0): seq[VkVertexInputBindingDescription] =
-  # packed attribute data, not interleaved (aks "struct of arrays")
-  var binding = bindingoffset
-  for name, value in T().fieldPairs:
-    when typeof(value) is InstanceAttribute:
-      let inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
-    elif typeof(value) is VertexAttribute:
-      let inputRate = VK_VERTEX_INPUT_RATE_VERTEX
-    else:
-      {.error: "Unsupported vertex attribute type".}
-    result.add(
-      VkVertexInputBindingDescription(
-        binding: uint32(binding),
-        stride: uint32(sizeof(getAttributeType(value))),
-        inputRate: inputRate,
-      )
-    )
-    binding += 1
-
-
-func generateInputAttributeBinding*[T](bindingoffset: int = 0, locationoffset: int = 0): seq[VkVertexInputAttributeDescription] =
-  # TODO:
-  var location = 0
-  var binding = bindingoffset
-  for name, value in T().fieldPairs:
-    when typeof(value) is VertexAttribute:
-      for i in 0 ..< compositeAttributesNumber[getAttributeType(value)]():
-        result.add(
-          VkVertexInputAttributeDescription(
-            binding: uint32(binding),
-            location: uint32(location),
-            format: getVkFormat[compositeAttributeType(getAttributeType(value))](),
-            offset: uint32(i * sizeof(compositeAttributeType(getAttributeType(value)))),
-          )
-        )
-        location += nLocationSlots[compositeAttributeType(getAttributeType(value))]()
-      binding += 1
--- a/src/semicongine/legacy/vulkan_helpers.nim	Thu Apr 27 00:23:23 2023 +0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,215 +0,0 @@
-import std/tables
-import std/strutils
-import std/strformat
-import std/logging
-import std/macros
-
-import ./vulkan
-import ./window
-
-# the included code need checkVkResult, therefore having the template above
-when defined(linux):
-  include ./platform/linux/vulkan
-when defined(windows):
-  include ./platform/windows/vulkan
-
-const ENABLEVULKANVALIDATIONLAYERS* = not defined(release)
-
-func addrOrNil[T](obj: var openArray[T]): ptr T =
-  if obj.len > 0: addr(obj[0]) else: nil
-
-func filterForSurfaceFormat*(formats: seq[VkSurfaceFormatKHR]): seq[VkSurfaceFormatKHR] =
-  for format in formats:
-    if format.format == VK_FORMAT_B8G8R8A8_SRGB and format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
-      result.add(format)
-
-func getSuitableSurfaceFormat*(formats: seq[VkSurfaceFormatKHR]): VkSurfaceFormatKHR =
-  let usableSurfaceFormats = filterForSurfaceFormat(formats)
-  if len(usableSurfaceFormats) == 0:
-    raise newException(Exception, "No suitable surface formats found")
-  return usableSurfaceFormats[0]
-
-
-func cleanString*(str: openArray[char]): string =
-  for i in 0 ..< len(str):
-    if str[i] == char(0):
-      result = join(str[0 ..< i])
-      break
-
-proc getInstanceExtensions*(): seq[string] =
-  var extensionCount: uint32
-  checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( extensionCount), nil)
-  var extensions = newSeq[VkExtensionProperties](extensionCount)
-  checkVkResult vkEnumerateInstanceExtensionProperties(nil, addr( extensionCount), addrOrNil(extensions))
-
-  for extension in extensions:
-    result.add(cleanString(extension.extensionName))
-
-
-proc getDeviceExtensions*(device: VkPhysicalDevice): seq[string] =
-  var extensionCount: uint32
-  checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(
-      extensionCount), nil)
-  var extensions = newSeq[VkExtensionProperties](extensionCount)
-  checkVkResult vkEnumerateDeviceExtensionProperties(device, nil, addr(
-      extensionCount), addrOrNil(extensions))
-
-  for extension in extensions:
-    result.add(cleanString(extension.extensionName))
-
-
-proc getValidationLayers*(): seq[string] =
-  var n_layers: uint32
-  checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), nil)
-  var layers = newSeq[VkLayerProperties](n_layers)
-  checkVkResult vkEnumerateInstanceLayerProperties(addr(n_layers), addrOrNil(layers))
-
-  for layer in layers:
-    result.add(cleanString(layer.layerName))
-
-
-proc getVulkanPhysicalDevices*(instance: VkInstance): seq[VkPhysicalDevice] =
-  var n_devices: uint32
-  checkVkResult vkEnumeratePhysicalDevices(instance, addr(n_devices), nil)
-  result = newSeq[VkPhysicalDevice](n_devices)
-  checkVkResult vkEnumeratePhysicalDevices(instance, addr(n_devices), addrOrNil(result))
-
-
-proc getQueueFamilies*(device: VkPhysicalDevice): seq[VkQueueFamilyProperties] =
-  var n_queuefamilies: uint32
-  vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies), nil)
-  result = newSeq[VkQueueFamilyProperties](n_queuefamilies)
-  vkGetPhysicalDeviceQueueFamilyProperties(device, addr(n_queuefamilies), addrOrNil(result))
-
-
-proc getDeviceSurfaceFormats*(device: VkPhysicalDevice, surface: VkSurfaceKHR): seq[VkSurfaceFormatKHR] =
-  var n_formats: uint32
-  checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, addr(n_formats), nil)
-  result = newSeq[VkSurfaceFormatKHR](n_formats)
-  checkVkResult vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, addr(n_formats), addrOrNil(result))
-
-
-proc getDeviceSurfacePresentModes*(device: VkPhysicalDevice,
-    surface: VkSurfaceKHR): seq[VkPresentModeKHR] =
-  var n_modes: uint32
-  checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, addr(
-      n_modes), nil)
-  result = newSeq[VkPresentModeKHR](n_modes)
-  checkVkResult vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, addr(
-      n_modes), addrOrNil(result))
-
-
-proc getSwapChainImages*(device: VkDevice, swapChain: VkSwapchainKHR): seq[VkImage] =
-  var n_images: uint32
-  checkVkResult vkGetSwapchainImagesKHR(device, swapChain, addr(n_images), nil)
-  result = newSeq[VkImage](n_images)
-  checkVkResult vkGetSwapchainImagesKHR(device, swapChain, addr(n_images), addr(
-      result[0]))
-
-
-func getPresentMode*(modes: seq[VkPresentModeKHR]): VkPresentModeKHR =
-  let preferredModes = [
-    VK_PRESENT_MODE_MAILBOX_KHR,      # triple buffering
-    VK_PRESENT_MODE_FIFO_RELAXED_KHR, # double duffering
-    VK_PRESENT_MODE_FIFO_KHR,         # double duffering
-    VK_PRESENT_MODE_IMMEDIATE_KHR,    # single buffering
-  ]
-  for preferredMode in preferredModes:
-    for mode in modes:
-      if preferredMode == mode:
-        return mode
-  # should never be reached, but seems to be garuanteed by vulkan specs to always be available
-  return VK_PRESENT_MODE_FIFO_KHR
-
-
-proc createVulkanInstance*(vulkanVersion: uint32): VkInstance =
-
-  var requiredExtensions = @["VK_KHR_surface".cstring] & REQUIRED_PLATFORM_EXTENSIONS
-  when ENABLEVULKANVALIDATIONLAYERS:
-    requiredExtensions.add("VK_EXT_debug_utils".cstring)
-
-  let availableExtensions = getInstanceExtensions()
-  for extension in requiredExtensions:
-    assert $extension in availableExtensions, $extension
-
-  let availableLayers = getValidationLayers()
-  var usableLayers = newSeq[cstring]()
-
-  when ENABLEVULKANVALIDATIONLAYERS:
-    const desiredLayers = ["VK_LAYER_KHRONOS_validation".cstring, "VK_LAYER_MESA_overlay".cstring]
-  else:
-    const desiredLayers: array[0, string] = []
-  for layer in desiredLayers:
-    if $layer in availableLayers:
-      usableLayers.add(layer)
-
-  echo "Available validation layers: ", availableLayers
-  echo "Using validation layers: ", usableLayers
-  echo "Available extensions: ", availableExtensions
-  echo "Using instance extensions: ", requiredExtensions
-
-  var appinfo = VkApplicationInfo(
-    sType: VK_STRUCTURE_TYPE_APPLICATION_INFO,
-    pApplicationName: "Hello Triangle",
-    pEngineName: "Custom engine",
-    apiVersion: vulkanVersion,
-  )
-  var createinfo = VkInstanceCreateInfo(
-    sType: VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
-    pApplicationInfo: addr(appinfo),
-    enabledLayerCount: usableLayers.len.uint32,
-    ppEnabledLayerNames: cast[ptr UncheckedArray[cstring]](addrOrNil(
-        usableLayers)),
-    enabledExtensionCount: requiredExtensions.len.uint32,
-    ppEnabledExtensionNames: cast[ptr UncheckedArray[cstring]](addr(
-        requiredExtensions[0]))
-  )
-  checkVkResult vkCreateInstance(addr(createinfo), nil, addr(result))
-  let other_extensions = @["VK_KHR_swapchain".cstring]
-  for extension in requiredExtensions & other_extensions:
-    result.loadExtension($extension)
-
-proc getVulcanDevice*(
-  physicalDevice: var VkPhysicalDevice,
-  features: var VkPhysicalDeviceFeatures,
-  graphicsQueueFamily: uint32,
-  presentationQueueFamily: uint32,
-): (VkDevice, VkQueue, VkQueue) =
-  # setup queue and device
-  # TODO: need check this, possibly wrong logic, see Vulkan tutorial
-  var priority = 1.0'f32
-  var queueCreateInfo = [
-    VkDeviceQueueCreateInfo(
-      sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
-      queueFamilyIndex: graphicsQueueFamily,
-      queueCount: 1,
-      pQueuePriorities: addr(priority),
-    ),
-  ]
-
-  var requiredExtensions = ["VK_KHR_swapchain".cstring]
-  var deviceCreateInfo = VkDeviceCreateInfo(
-    sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
-    queueCreateInfoCount: uint32(queueCreateInfo.len),
-    pQueueCreateInfos: addrOrNil(queueCreateInfo),
-    pEnabledFeatures: addr(features),
-    enabledExtensionCount: requiredExtensions.len.uint32,
-    ppEnabledExtensionNames: cast[ptr UncheckedArray[cstring]](addr(requiredExtensions))
-  )
-  checkVkResult vkCreateDevice(physicalDevice, addr(deviceCreateInfo), nil,
-      addr(result[0]))
-  vkGetDeviceQueue(result[0], graphicsQueueFamily, 0'u32, addr(result[1]))
-  vkGetDeviceQueue(result[0], presentationQueueFamily, 0'u32, addr(result[2]))
-
-proc debugCallback*(
-  messageSeverity: VkDebugUtilsMessageSeverityFlagBitsEXT,
-  messageTypes: VkDebugUtilsMessageTypeFlagsEXT,
-  pCallbackData: ptr VkDebugUtilsMessengerCallbackDataEXT,
-  userData: pointer
-): VkBool32 {.cdecl.} =
-  echo &"{messageSeverity}: {VkDebugUtilsMessageTypeFlagBitsEXT(messageTypes)}: {pCallbackData.pMessage}"
-  return false
-
-proc getSurfaceCapabilities*(device: VkPhysicalDevice,
-    surface: VkSurfaceKHR): VkSurfaceCapabilitiesKHR =
-  checkVkResult device.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(surface, addr(result))