Mercurial > games > semicongine
diff src/vertex.nim @ 17:b40466fa446a
add: vertex basics, some refactoring
author | Sam <sam@basx.dev> |
---|---|
date | Sun, 01 Jan 2023 01:00:50 +0700 |
parents | a571db114152 |
children |
line wrap: on
line diff
--- a/src/vertex.nim Fri Dec 30 15:56:17 2022 +0700 +++ b/src/vertex.nim Sun Jan 01 01:00:50 2023 +0700 @@ -1,5 +1,179 @@ +import std/macros +import std/strutils +import std/strformat +import std/typetraits + +import ./math/vector +import ./vulkan + type - VertexAttribute = object + VertexAttributeType = SomeNumber|Vec + VertexAttribute*[T:VertexAttributeType] = object + + +# from https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html +func nLocationSlots[T: VertexAttributeType](): int = + when (T is Vec3[float64] or T is Vec3[uint64] or T is Vec4[float64] or T is Vec4[float64]): + 2 + else: + 1 + +# 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 Vec2[uint8]: VK_FORMAT_R8G8_UINT + elif T is Vec2[int8]: VK_FORMAT_R8G8_SINT + elif T is Vec2[uint16]: VK_FORMAT_R16G16_UINT + elif T is Vec2[int16]: VK_FORMAT_R16G16_SINT + elif T is Vec2[uint32]: VK_FORMAT_R32G32_UINT + elif T is Vec2[int32]: VK_FORMAT_R32G32_SINT + elif T is Vec2[uint64]: VK_FORMAT_R64G64_UINT + elif T is Vec2[int64]: VK_FORMAT_R64G64_SINT + elif T is Vec2[float32]: VK_FORMAT_R32G32_SFLOAT + elif T is Vec2[float64]: VK_FORMAT_R64G64_SFLOAT + elif T is Vec3[uint8]: VK_FORMAT_R8G8B8_UINT + elif T is Vec3[int8]: VK_FORMAT_R8G8B8_SINT + elif T is Vec3[uint16]: VK_FORMAT_R16G16B16_UINT + elif T is Vec3[int16]: VK_FORMAT_R16G16B16_SINT + elif T is Vec3[uint32]: VK_FORMAT_R32G32B32_UINT + elif T is Vec3[int32]: VK_FORMAT_R32G32B32_SINT + elif T is Vec3[uint64]: VK_FORMAT_R64G64B64_UINT + elif T is Vec3[int64]: VK_FORMAT_R64G64B64_SINT + elif T is Vec3[float32]: VK_FORMAT_R32G32B32_SFLOAT + elif T is Vec3[float64]: VK_FORMAT_R64G64B64_SFLOAT + elif T is Vec4[uint8]: VK_FORMAT_R8G8B8A8_UINT + elif T is Vec4[int8]: VK_FORMAT_R8G8B8A8_SINT + elif T is Vec4[uint16]: VK_FORMAT_R16G16B16A16_UINT + elif T is Vec4[int16]: VK_FORMAT_R16G16B16A16_SINT + elif T is Vec4[uint32]: VK_FORMAT_R32G32B32A32_UINT + elif T is Vec4[int32]: VK_FORMAT_R32G32B32A32_SINT + elif T is Vec4[uint64]: VK_FORMAT_R64G64B64A64_UINT + elif T is Vec4[int64]: VK_FORMAT_R64G64B64A64_SINT + elif T is Vec4[float32]: VK_FORMAT_R32G32B32A32_SFLOAT + elif T is Vec4[float64]: VK_FORMAT_R64G64B64A64_SFLOAT + +func getGLSLType[T: VertexAttributeType](): 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 Vec2[uint8]: "uvec2" + elif T is Vec2[int8]: "ivec2" + elif T is Vec2[uint16]: "uvec2" + elif T is Vec2[int16]: "ivec2" + elif T is Vec2[uint32]: "uvec2" + elif T is Vec2[int32]: "ivec2" + elif T is Vec2[uint64]: "uvec2" + elif T is Vec2[int64]: "ivec2" + elif T is Vec2[float32]: "vec2" + elif T is Vec2[float64]: "dvec2" - VertexType = object + elif T is Vec3[uint8]: "uvec3" + elif T is Vec3[int8]: "ivec3" + elif T is Vec3[uint16]: "uvec3" + elif T is Vec3[int16]: "ivec3" + elif T is Vec3[uint32]: "uvec3" + elif T is Vec3[int32]: "ivec3" + elif T is Vec3[uint64]: "uvec3" + elif T is Vec3[int64]: "ivec3" + elif T is Vec3[float32]: "vec3" + elif T is Vec3[float64]: "dvec3" + + elif T is Vec4[uint8]: "uvec4" + elif T is Vec4[int8]: "ivec4" + elif T is Vec4[uint16]: "uvec4" + elif T is Vec4[int16]: "ivec4" + elif T is Vec4[uint32]: "uvec4" + elif T is Vec4[int32]: "ivec4" + elif T is Vec4[uint64]: "uvec4" + elif T is Vec4[int64]: "ivec4" + elif T is Vec4[float32]: "vec4" + elif T is Vec4[float64]: "dvec4" + +template rawAttributeType(v: VertexAttribute): auto = get(genericParams(typeof(v)), 0) + +func generateGLSL[T](): string = + var stmtList: seq[string] + var i = 0 + for name, value in T().fieldPairs: + when typeof(value) is VertexAttribute: + let glsltype = getGLSLType[rawAttributeType(value)]() + let n = name + stmtList.add(&"layout(location = {i}) in {glsltype} {n};") + i += nLocationSlots[rawAttributeType(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 VertexAttribute: + result.add( + VkVertexInputBindingDescription( + binding: uint32(binding), + stride: uint32(sizeof(rawAttributeType(value))), + inputRate: VK_VERTEX_INPUT_RATE_VERTEX, # VK_VERTEX_INPUT_RATE_INSTANCE for instances + ) + ) + binding += 1 + +func generateInputAttributeBinding*[T](bindingoffset: int = 0, locationoffset: int = 0): seq[VkVertexInputAttributeDescription] = + # packed attribute data, not interleaved (aks "struct of arrays") + var location = 0 + var binding = bindingoffset + for name, value in T().fieldPairs: + when typeof(value) is VertexAttribute: + result.add( + VkVertexInputAttributeDescription( + binding: uint32(binding), + location: uint32(location), + format: getVkFormat[rawAttributeType(value)](), + offset: 0, + ) + ) + location += nLocationSlots[rawAttributeType(value)]() + binding += 1 + +func getBindingDescription(binding: int): auto = + VkVertexInputBindingDescription( + binding: uint32(binding), + stride: 0, # either sizeof of vertex (array of structs) or of attribute (struct of arrays) + inputRate: VK_VERTEX_INPUT_RATE_VERTEX, # VK_VERTEX_INPUT_RATE_INSTANCE for instances + ) + +func getAttributeDescriptions(binding: int): auto = + [ + VkVertexInputAttributeDescription( + binding: 0'u32, + location: 0, + format: VK_FORMAT_R32G32_SFLOAT, + offset: 0, + ), + VkVertexInputAttributeDescription( + binding: 0'u32, + location: 1, + format: VK_FORMAT_R32G32B32_SFLOAT, + offset: uint32(sizeof(Vec2)), # use offsetOf? + ), + ]