Mercurial > games > semicongine
changeset 1377:aaf8fa2c7bb2
merge
author | sam <sam@basx.dev> |
---|---|
date | Sun, 08 Dec 2024 08:21:27 +0700 |
parents | cd2455307a6c (current diff) ca3299ea1bdf (diff) |
children | 31f57a969ffd |
files | |
diffstat | 10 files changed, 348 insertions(+), 107 deletions(-) [+] |
line wrap: on
line diff
--- a/semicongine/contrib/algorithms/texture_packing.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/semicongine/contrib/algorithms/texture_packing.nim Sun Dec 08 08:21:27 2024 +0700 @@ -84,10 +84,10 @@ for y in 0 ..< rect.h: for x in 0 ..< rect.w: when T is Gray: - assert result.atlas[rect.x + x, rect.y + y] == [0'u8], + assert result.atlas[rect.x + x, rect.y + y] == default(T), "Atlas texture packing encountered an overlap error" elif T is BGRA: - assert result.atlas[rect.x + x, rect.y + y] == [0'u8, 0'u8, 0'u8, 0'u8], + assert result.atlas[rect.x + x, rect.y + y] == default(T), "Atlas texture packing encountered an overlap error" else: {.error: "Unsupported type for texture packing".}
--- a/semicongine/core.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/semicongine/core.nim Sun Dec 08 08:21:27 2024 +0700 @@ -1,3 +1,4 @@ +import std/hashes import std/macros import std/math import std/monotimes
--- a/semicongine/core/vector.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/semicongine/core/vector.nim Sun Dec 08 08:21:27 2024 +0700 @@ -1,8 +1,8 @@ type - TVec1*[T: SomeNumber] = array[1, T] - TVec2*[T: SomeNumber] = array[2, T] - TVec3*[T: SomeNumber] = array[3, T] - TVec4*[T: SomeNumber] = array[4, T] + TVec1*[T: SomeNumber] = distinct array[1, T] + TVec2*[T: SomeNumber] = distinct array[2, T] + TVec3*[T: SomeNumber] = distinct array[3, T] + TVec4*[T: SomeNumber] = distinct array[4, T] TVec* = TVec1 | TVec2 | TVec3 | TVec4 Vec1f* = TVec1[float32] Vec2f* = TVec2[float32] @@ -18,8 +18,116 @@ Vec4u* = TVec4[uint32] # support for shorts + Vec1i8* = TVec1[int8] + Vec1u8* = TVec1[uint8] Vec2i8* = TVec2[int8] + Vec2u8* = TVec2[uint8] Vec3i8* = TVec3[int8] + Vec3u8* = TVec3[uint8] + +# stuff to allow working like an array, despite 'distinct' + +converter toArray*[T](v: TVec1[T]): array[1, T] = + array[1, T](v) + +converter toArray*[T](v: TVec2[T]): array[2, T] = + array[2, T](v) + +converter toArray*[T](v: TVec3[T]): array[3, T] = + array[3, T](v) + +converter toArray*[T](v: TVec4[T]): array[4, T] = + array[4, T](v) + +template `[]`*[T](v: TVec1[T], i: Ordinal): T = + (array[1, T](v))[i] + +template `[]`*[T](v: TVec2[T], i: Ordinal): T = + (array[2, T](v))[i] + +template `[]`*[T](v: TVec3[T], i: Ordinal): T = + (array[3, T](v))[i] + +template `[]`*[T](v: TVec4[T], i: Ordinal): T = + (array[4, T](v))[i] + +template `[]=`*[T](v: TVec1[T], i: Ordinal, a: T) = + (array[1, T](v))[i] = a + +template `[]=`*[T](v: TVec2[T], i: Ordinal, a: T) = + (array[2, T](v))[i] = a + +template `[]=`*[T](v: TVec3[T], i: Ordinal, a: T) = + (array[3, T](v))[i] = a + +template `[]=`*[T](v: TVec4[T], i: Ordinal, a: T) = + (array[4, T](v))[i] = a + +template `==`*[T](a, b: TVec1[T]): bool = + `==`(array[1, T](a), array[1, T](b)) + +template `==`*[T](a, b: TVec2[T]): bool = + `==`(array[2, T](a), array[2, T](b)) + +template `==`*[T](a, b: TVec3[T]): bool = + `==`(array[3, T](a), array[3, T](b)) + +template `==`*[T](a, b: TVec4[T]): bool = + `==`(array[4, T](a), array[4, T](b)) + +func len*(v: TVec1): int = + 1 +func len*(v: TVec2): int = + 2 +func len*(v: TVec3): int = + 3 +func len*(v: TVec4): int = + 4 + +func `$`*[T](v: TVec1[T]): string = + `$`(array[1, T](v)) +func `$`*[T](v: TVec2[T]): string = + `$`(array[2, T](v)) +func `$`*[T](v: TVec3[T]): string = + `$`(array[3, T](v)) +func `$`*[T](v: TVec4[T]): string = + `$`(array[4, T](v)) + +func sum*[T](v: TVec1[T]): T = + sum(array[1, T](v)) +func sum*[T](v: TVec2[T]): T = + sum(array[2, T](v)) +func sum*[T](v: TVec3[T]): T = + sum(array[3, T](v)) +func sum*[T](v: TVec4[T]): T = + sum(array[4, T](v)) + +func hash*[T](v: TVec1[T]): Hash = + hash(array[1, T](v)) +func hash*[T](v: TVec2[T]): Hash = + hash(array[2, T](v)) +func hash*[T](v: TVec3[T]): Hash = + hash(array[3, T](v)) +func hash*[T](v: TVec4[T]): Hash = + hash(array[4, T](v)) + +iterator items*[T](v: TVec1[T]): T = + yield v[0] + +iterator items*[T](v: TVec2[T]): T = + yield v[0] + yield v[1] + +iterator items*[T](v: TVec3[T]): T = + yield v[0] + yield v[1] + yield v[2] + +iterator items*[T](v: TVec4[T]): T = + yield v[0] + yield v[1] + yield v[2] + yield v[3] func toVec1*[T: SomeNumber](orig: TVec3[T] | TVec4[T]): TVec1[T] = TVec1[T]([orig[0]]) @@ -94,12 +202,23 @@ vec4i(0, 0, 0, 0) # shortcuts Vec3i8 +func vec1i8*[T: SomeInteger](x: T): Vec1i8 = + Vec1i8([int8(x)]) +func vec1i8*(): Vec1i8 = + vec1i8(0) +func vec1u8*[T: SomeInteger](x: T): Vec1u8 = + Vec1u8([uint8(x)]) +func vec1u8*(): Vec1u8 = + vec1u8(0) + +# missing: unsigned ones func vec2i8*[T, S: SomeInteger](x: T, y: S): Vec2i8 = Vec2i8([int8(x), int8(y)]) func vec2i8*[T: SomeInteger](x: T): Vec2i8 = vec2i8(x, 0) func vec2i8*(): Vec2i8 = vec2i8(0, 0) + func vec3i8*[T, S, U: SomeInteger](x: T, y: S, z: U): Vec3i8 = Vec3i8([int8(x), int8(y), int8(z)]) func vec3i8*[T, S: SomeInteger](x: T, y: S): Vec3i8 =
--- a/semicongine/rendering.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/semicongine/rendering.nim Sun Dec 08 08:21:27 2024 +0700 @@ -131,6 +131,8 @@ IndexBufferMapped UniformBuffer UniformBufferMapped + StorageBuffer + StorageBufferMapped MemoryBlock* = object vk: VkDeviceMemory @@ -187,42 +189,58 @@ proc `[]=`*[T, S](a: var GPUArray[T, S], i: SomeInteger, value: T) = a.data[i] = value -template forDescriptorFields( - shader: typed, valuename, typename, countname, bindingNumber, body: untyped -): untyped = - var `bindingNumber` {.inject.} = 0'u32 - for theFieldname, `valuename` in fieldPairs(shader): - when typeof(`valuename`) is ImageObject: - block: - const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER - const `countname` {.inject.} = 1'u32 - body - `bindingNumber`.inc - elif typeof(`valuename`) is GPUValue: - block: - const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER - const `countname` {.inject.} = 1'u32 - body - `bindingNumber`.inc - elif typeof(`valuename`) is array: - when elementType(`valuename`) is ImageObject: - block: - const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER - const `countname` {.inject.} = uint32(typeof(`valuename`).len) - body - `bindingNumber`.inc - elif elementType(`valuename`) is GPUValue: - block: - const `typename` {.inject.} = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER - const `countname` {.inject.} = len(`valuename`).uint32 - body - `bindingNumber`.inc +func getBufferType*[A, B](value: GPUValue[A, B]): BufferType {.compileTime.} = + B + +func getBufferType*[A, B]( + value: openArray[GPUValue[A, B]] +): BufferType {.compileTime.} = + B + +func getDescriptorType[T](): VkDescriptorType {.compileTIme.} = + when T is ImageObject: + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER + elif T is GPUValue: + when getBufferType(default(T)) in [UniformBuffer, UniformBufferMapped]: + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER + elif getBufferType(default(T)) in [StorageBuffer, StorageBufferMapped]: + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER + else: + {.error: "Unsupported descriptor type: " & typetraits.name(T).} + elif T is array: + when elementType(default(T)) is ImageObject: + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER + elif elementType(default(T)) is GPUValue: + when getBufferType(default(elementType(default(T)))) in + [UniformBuffer, UniformBufferMapped]: + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER + elif getBufferType(default(elementType(default(T)))) in + [StorageBuffer, StorageBufferMapped]: + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER else: - {. - error: "Unsupported descriptor type: " & typetraits.name(typeof(`valuename`)) - .} + {.error: "Unsupported descriptor type: " & typetraits.name(T).} else: - {.error: "Unsupported descriptor type: " & typetraits.name(typeof(`valuename`)).} + {.error: "Unsupported descriptor type: " & typetraits.name(T).} + else: + {.error: "Unsupported descriptor type: " & typetraits.name(T).} + +func getDescriptorCount[T](): uint32 {.compileTIme.} = + when T is array: + len(T) + else: + 1 + +func getBindingNumber[T](field: static string): uint32 {.compileTime.} = + var c = 0'u32 + var found = false + for name, value in fieldPairs(default(T)): + when name == field: + result = c + found = true + else: + inc c + assert found, + "Field '" & field & "' of descriptor '" & typetraits.name(T) & "' not found" proc currentFiF*(): int = assert vulkan.swapchain != nil, "Swapchain has not been initialized yet" @@ -385,7 +403,8 @@ initSwapchain(renderPass, vSync = vSync, tripleBuffering = tripleBuffering) proc destroyVulkan*() = - clearSwapchain() + if vulkan.swapchain != nil: + clearSwapchain() vkDestroyDevice(vulkan.device, nil) vkDestroySurfaceKHR(vulkan.instance, vulkan.surface, nil) if vulkan.debugMessenger.Valid:
--- a/semicongine/rendering/renderer.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/semicongine/rendering/renderer.nim Sun Dec 08 08:21:27 2024 +0700 @@ -1,20 +1,16 @@ func pointerAddOffset[T: SomeInteger](p: pointer, offset: T): pointer = cast[pointer](cast[T](p) + offset) -func usage(bType: BufferType): seq[VkBufferUsageFlagBits] = - case bType - of VertexBuffer: - @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] - of VertexBufferMapped: - @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT] - of IndexBuffer: - @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] - of IndexBufferMapped: - @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT] - of UniformBuffer: - @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT] - of UniformBufferMapped: - @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT] +const BUFFER_USAGE: array[BufferType, seq[VkBufferUsageFlagBits]] = [ + VertexBuffer: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT], + VertexBufferMapped: @[VK_BUFFER_USAGE_VERTEX_BUFFER_BIT], + IndexBuffer: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT], + IndexBufferMapped: @[VK_BUFFER_USAGE_INDEX_BUFFER_BIT], + UniformBuffer: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT], + UniformBufferMapped: @[VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT], + StorageBuffer: @[VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_BUFFER_USAGE_TRANSFER_DST_BIT], + StorageBufferMapped: @[VK_BUFFER_USAGE_STORAGE_BUFFER_BIT], +] proc getVkFormat(grayscale: bool, usage: openArray[VkImageUsageFlagBits]): VkFormat = let formats = @@ -56,7 +52,8 @@ typeof(gpuData).TBuffer func needsMapping(bType: BufferType): bool = - bType in [VertexBufferMapped, IndexBufferMapped, UniformBufferMapped] + bType in + [VertexBufferMapped, IndexBufferMapped, UniformBufferMapped, StorageBufferMapped] template needsMapping(gpuData: GPUData): untyped = gpuData.bufferType.needsMapping @@ -127,16 +124,17 @@ var imageWrites = newSeqOfCap[VkDescriptorImageInfo](1024) var bufferWrites = newSeqOfCap[VkDescriptorBufferInfo](1024) - forDescriptorFields( - descriptorSet.data, fieldValue, descriptorType, descriptorCount, - descriptorBindingNumber, - ): + for theFieldname, fieldvalue in fieldPairs(descriptorSet.data): + const descriptorType = getDescriptorType[typeof(fieldvalue)]() + const descriptorCount = getDescriptorCount[typeof(fieldvalue)]() + const descriptorBindingNumber = + getBindingNumber[typeof(descriptorSet.data)](theFieldname) for i in 0 ..< descriptorSet.vk.len: - when typeof(fieldValue) is GPUValue: + when typeof(fieldvalue) is GPUValue: bufferWrites.add VkDescriptorBufferInfo( - buffer: fieldValue.buffer.vk, - offset: fieldValue.offset, - range: fieldValue.size, + buffer: fieldvalue.buffer.vk, + offset: fieldvalue.offset, + range: fieldvalue.size, ) descriptorSetWrites.add VkWriteDescriptorSet( sType: VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, @@ -148,10 +146,10 @@ pImageInfo: nil, pBufferInfo: addr(bufferWrites[^1]), ) - elif typeof(fieldValue) is ImageObject: + elif typeof(fieldvalue) is ImageObject: imageWrites.add VkDescriptorImageInfo( - sampler: fieldValue.sampler, - imageView: fieldValue.imageView, + sampler: fieldvalue.sampler, + imageView: fieldvalue.imageView, imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, ) descriptorSetWrites.add VkWriteDescriptorSet( @@ -164,9 +162,9 @@ pImageInfo: addr(imageWrites[^1]), pBufferInfo: nil, ) - elif typeof(fieldValue) is array: - when elementType(fieldValue) is ImageObject: - for image in fieldValue.litems: + elif typeof(fieldvalue) is array: + when elementType(fieldvalue) is ImageObject: + for image in fieldvalue.litems: imageWrites.add VkDescriptorImageInfo( sampler: image.sampler, imageView: image.imageView, @@ -182,8 +180,8 @@ pImageInfo: addr(imageWrites[^descriptorCount.int]), pBufferInfo: nil, ) - elif elementType(fieldValue) is GPUValue: - for entry in fieldValue.litems: + elif elementType(fieldvalue) is GPUValue: + for entry in fieldvalue.litems: bufferWrites.add VkDescriptorBufferInfo( buffer: entry.buffer.vk, offset: entry.offset, range: entry.size ) @@ -199,11 +197,11 @@ ) else: {. - error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldValue)) + error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue)) .} else: {. - error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldValue)) + error: "Unsupported descriptor type: " & typetraits.name(typeof(fieldvalue)) .} vkUpdateDescriptorSets( @@ -259,7 +257,7 @@ renderData: var RenderData, size: uint64, bufferType: BufferType ): Buffer = result = Buffer( - vk: svkCreateBuffer(size, bufferType.usage), + vk: svkCreateBuffer(size, BUFFER_USAGE[bufferType]), size: size, rawPointer: nil, offsetNextFree: 0, @@ -394,6 +392,9 @@ VkDescriptorPoolSize( thetype: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, descriptorCount: descriptorPoolLimit ), + VkDescriptorPoolSize( + thetype: VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, descriptorCount: descriptorPoolLimit + ), ] var poolInfo = VkDescriptorPoolCreateInfo( sType: VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, @@ -504,13 +505,14 @@ proc createVulkanImage(renderData: var RenderData, image: var ImageObject) = assert image.vk == VkImage(0), "Image has already been created" - var usage = @[VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_USAGE_SAMPLED_BIT] + var imgUsage = @[VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_USAGE_SAMPLED_BIT] if image.isRenderTarget: - usage.add VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT - let format = getVkFormat(grayscale = elementType(image.data) is Gray, usage = usage) + imgUsage.add VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + let format = + getVkFormat(grayscale = elementType(image.data) is Gray, usage = imgUsage) image.vk = svkCreate2DImage( - image.width, image.height, format, usage, image.samples, image.nLayers + image.width, image.height, format, imgUsage, image.samples, image.nLayers ) renderData.images.add image.vk image.sampler = createSampler(
--- a/semicongine/rendering/shaders.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/semicongine/rendering/shaders.nim Sun Dec 08 08:21:27 2024 +0700 @@ -79,6 +79,9 @@ const n = typetraits.name(T) {.error: "Unsupported data type on GPU: " & n.} +func glslType[T: SupportedGPUType](value: openArray[T]): string = + return glslType(default(T)) & "[]" + func vkType[T: SupportedGPUType](value: T): VkFormat = when T is float32: VK_FORMAT_R32_SFLOAT @@ -204,6 +207,12 @@ else: return 1 +func assertGPUType[T](t: T) = + assert T is SupportedGPUType, "'" & $(t) & "' is not a supported GPU type" + +func assertGPUType[T](t: openArray[T]) = + assert T is SupportedGPUType, "'" & $(t) & "' is not a supported GPU type" + proc generateShaderSource[TShader](shader: TShader): (string, string) {.compileTime.} = const GLSL_VERSION = "450" var vsInput: seq[string] @@ -264,12 +273,23 @@ ") uniform " & glslType(descriptorValue) & " " & descriptorName & ";" descriptorBinding.inc elif typeof(descriptorValue) is GPUValue: + let bufferType = + if getBufferType(descriptorValue) in [UniformBuffer, UniformBufferMapped]: + "uniform" + else: + "readonly buffer" uniforms.add "layout(set=" & $setIndex & ", binding = " & $descriptorBinding & - ") uniform T" & descriptorName & " {" + ") " & bufferType & " T" & descriptorName & " {" when typeof(descriptorValue.data) is object: - for blockFieldName, blockFieldValue in descriptorValue.data.fieldPairs(): - assert typeof(blockFieldValue) is SupportedGPUType, - "uniform block field '" & blockFieldName & "' is not a SupportedGPUType" + for blockFieldName, blockFieldValue in fieldPairs(descriptorValue.data): + when typeof(blockFieldValue) is array: + assert elementType(blockFieldValue) is SupportedGPUType, + bufferType & " block field '" & blockFieldName & + "' is not a SupportedGPUType" + else: + assert typeof(blockFieldValue) is SupportedGPUType, + bufferType & " block field '" & blockFieldName & + "' is not a SupportedGPUType" uniforms.add " " & glslType(blockFieldValue) & " " & blockFieldName & ";" uniforms.add "} " & descriptorName & ";" else: @@ -287,13 +307,18 @@ descriptorName & "" & arrayDecl & ";" descriptorBinding.inc elif elementType(descriptorValue) is GPUValue: + let bufferType = + if getBufferType(descriptorValue) in [UniformBuffer, UniformBufferMapped]: + "uniform" + else: + "readonly buffer" uniforms.add "layout(set=" & $setIndex & ", binding = " & $descriptorBinding & - ") uniform T" & descriptorName & " {" + ") " & bufferType & " T" & descriptorName & " {" - for blockFieldName, blockFieldValue in default(elementType(descriptorValue)).data - .fieldPairs(): - assert typeof(blockFieldValue) is SupportedGPUType, - "uniform block field '" & blockFieldName & "' is not a SupportedGPUType" + for blockFieldName, blockFieldValue in fieldPairs( + default(elementType(descriptorValue)).data + ): + assertGPUType(blockFieldValue) uniforms.add " " & glslType(blockFieldValue) & " " & blockFieldName & ";" uniforms.add "} " & descriptorName & "[" & $descriptorValue.len & "];" descriptorBinding.inc @@ -306,7 +331,7 @@ assert value is object, "push constants need to be objects" pushConstants.add "layout( push_constant ) uniform constants" pushConstants.add "{" - for constFieldName, constFieldValue in value.fieldPairs(): + for constFieldName, constFieldValue in fieldPairs(value): assert typeof(constFieldValue) is SupportedGPUType, "push constant field '" & constFieldName & "' is not a SupportedGPUType" pushConstants.add " " & glslType(constFieldValue) & " " & constFieldName & ";" @@ -423,13 +448,11 @@ for _, value in fieldPairs(default(TShader)): when hasCustomPragma(value, DescriptorSet): var layoutbindings: seq[VkDescriptorSetLayoutBinding] - forDescriptorFields( - value, fieldValue, descriptorType, descriptorCount, descriptorBindingNumber - ): + for theFieldname, fieldvalue in fieldPairs(value): layoutbindings.add VkDescriptorSetLayoutBinding( - binding: descriptorBindingNumber, - descriptorType: descriptorType, - descriptorCount: descriptorCount, + binding: getBindingNumber[typeof(value)](theFieldname), + descriptorType: getDescriptorType[typeof(fieldvalue)](), + descriptorCount: getDescriptorCount[typeof(fieldvalue)](), stageFlags: VkShaderStageFlags(VK_SHADER_STAGE_ALL_GRAPHICS), pImmutableSamplers: nil, )
--- a/semicongine/text.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/semicongine/text.nim Sun Dec 08 08:21:27 2024 +0700 @@ -69,6 +69,45 @@ color = vec4(textbox.color.rgb, textbox.color.a * v); }""" + GlyphDescriptors[N: static int] = object + fontAtlas: Image[Gray] + uvs1: array[N, Vec2f] + uvs2: array[N, Vec2f] + vertexPos1: array[N, Vec2f] + vertexPos2: array[N, Vec2f] + + GlyphShader*[N: static int] = object + position {.InstanceAttribute.}: Vec3f + color {.InstanceAttribute.}: Vec4f + scale {.InstanceAttribute.}: float32 + glyphIndex {.InstanceAttribute.}: uint16 + + fragmentUv {.Pass.}: Vec2f + fragmentColor {.PassFlat.}: Vec4f + outColor {.ShaderOutput.}: Vec4f + glyphData {.DescriptorSet: 0.}: GlyphDescriptors[N] + vertexCode* = + """void main() { + vec2 uv1 = uvs1[glyphIndex]; + vec2 uv2 = uvs2[glyphIndex]; + vec2 p1 = vertexPos1[glyphIndex]; + vec2 p2 = vertexPos2[glyphIndex]; + uv1[gl_VertexIndex % ] + + gl_Position = vec4(position * vec3(textbox.scale, 1) + textbox.position, 1.0); + fragmentUv = uv; + fragmentColor = color; +} """ + fragmentCode* = + """void main() { + float v = texture(fontAtlas, fragmentUv).r; + // CARFULL: This can lead to rough edges at times + if(v == 0) { + discard; + } + outColor = vec4(fragmentColor.rgb, fragmentColor.a * v); +}""" + proc `=copy`(dest: var FontObj, source: FontObj) {.error.} include ./text/font
--- a/semicongine/text/font.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/semicongine/text/font.nim Sun Dec 08 08:21:27 2024 +0700 @@ -97,10 +97,10 @@ if width > 0 and height > 0: var bitmap = newSeq[Gray](width * height) for i in 0 ..< width * height: - bitmap[i] = [data[i].uint8] + bitmap[i] = vec1u8(data[i].uint8) images.add Image[Gray](width: width.uint32, height: height.uint32, data: bitmap) else: - images.add Image[Gray](width: 1, height: 1, data: @[[0'u8]]) + images.add Image[Gray](width: 1, height: 1, data: @[vec1u8()]) nativeFree(data)
--- a/tests/test_rendering.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/tests/test_rendering.nim Sun Dec 08 08:21:27 2024 +0700 @@ -1032,24 +1032,24 @@ setupSwapchain(renderpass = renderpass) # tests a simple triangle with minimalistic shader and vertex format - # test_01_triangle(time) + test_01_triangle(time) # tests instanced triangles and quads, mixing meshes and instances - # test_02_triangle_quad_instanced(time) + test_02_triangle_quad_instanced(time) # teste descriptor sets - # test_03_simple_descriptorset(time) + test_03_simple_descriptorset(time) # tests multiple descriptor sets and arrays - # test_04_multiple_descriptorsets(time) + test_04_multiple_descriptorsets(time) # rotating cube - # test_05_cube(time) + test_05_cube(time) # different draw modes (lines, points, and topologies) - # test_06_different_draw_modes(time) + test_06_different_draw_modes(time) - # test_07_png_texture(time) + test_07_png_texture(time) test_08_texture_array(time) @@ -1058,7 +1058,7 @@ clearSwapchain() # test multiple render passes - # for i, (depthBuffer, samples) in renderPasses: - # test_09_triangle_2pass(time, depthBuffer, samples) + for i, (depthBuffer, samples) in renderPasses: + test_09_triangle_2pass(time, depthBuffer, samples) destroyVulkan()
--- a/tests/test_text.nim Sun Dec 08 08:20:36 2024 +0700 +++ b/tests/test_text.nim Sun Dec 08 08:21:27 2024 +0700 @@ -12,6 +12,36 @@ type FontDS = object fontAtlas: Image[Gray] +proc test_01_static_label_new(time: float32) = + var font = loadFont("Overhaul.ttf", lineHeightPixels = 160) + var renderdata = initRenderData() + var pipeline = + createPipeline[GlyphShader[200]](renderPass = vulkan.swapchain.renderPass) + + var ds = asDescriptorSetData(GlyphDescriptors[200](fontAtlas: font.fontAtlas.copy())) + uploadImages(renderdata, ds) + initDescriptorSet(renderdata, pipeline.layout(0), ds) + + var start = getMonoTime() + while ((getMonoTime() - start).inMilliseconds().int / 1000) < time: + withNextFrame(framebuffer, commandbuffer): + bindDescriptorSet(commandbuffer, ds, 0, pipeline) + withRenderPass( + vulkan.swapchain.renderPass, + framebuffer, + commandbuffer, + vulkan.swapchain.width, + vulkan.swapchain.height, + vec4(0, 0, 0, 0), + ): + withPipeline(commandbuffer, pipeline): + render(commandbuffer, pipeline, label1, vec3(), vec4(1, 1, 1, 1)) + + # cleanup + checkVkResult vkDeviceWaitIdle(vulkan.device) + destroyPipeline(pipeline) + destroyRenderData(renderdata) + proc test_01_static_label(time: float32) = var font = loadFont("Overhaul.ttf", lineHeightPixels = 160) var renderdata = initRenderData() @@ -39,7 +69,14 @@ vec4(0, 0, 0, 0), ): withPipeline(commandbuffer, pipeline): - render(commandbuffer, pipeline, label1, vec3(), vec4(1, 1, 1, 1)) + proc render( + commandBuffer = commandbuffer, + pipeline = pipeline, + mesh: TMesh, + instances: TInstance, + fixedVertexCount = -1, + fixedInstanceCount = -1, + ) # cleanup checkVkResult vkDeviceWaitIdle(vulkan.device) @@ -250,6 +287,7 @@ setupSwapchain(renderpass = renderpass) # tests a simple triangle with minimalistic shader and vertex format + test_01_static_label_new(time) test_01_static_label(time) test_02_multiple_animated(time) test_03_layouting(time)