Mercurial > games > semicongine
view src/semicongine/vertex.nim @ 103:1e2027dfc642
add: finally working initial approach for shader definitions
author | Sam <sam@basx.dev> |
---|---|
date | Mon, 20 Mar 2023 10:25:50 +0700 |
parents | 4deffc94484a |
children |
line wrap: on
line source
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