changeset 211:744285b47a4d

did: refactor image handling
author Sam <sam@basx.dev>
date Tue, 09 May 2023 19:52:57 +0700
parents f3912838cd69
children 77755701bf49
files src/semicongine/core.nim src/semicongine/core/imagetypes.nim src/semicongine/engine.nim src/semicongine/entity.nim src/semicongine/renderer.nim src/semicongine/vulkan/image.nim src/semicongine/vulkan/renderpass.nim src/semicongine/vulkan/swapchain.nim tests/test_materials.nim tests/test_vulkan_wrapper.nim
diffstat 10 files changed, 58 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/core.nim	Tue May 09 18:19:17 2023 +0700
+++ b/src/semicongine/core.nim	Tue May 09 19:52:57 2023 +0700
@@ -6,6 +6,7 @@
 import ./core/buildconfig
 import ./core/color
 import ./core/gpu_data
+import ./core/imagetypes
 import ./core/matrix
 import ./core/vector
 import ./core/utils
@@ -15,6 +16,7 @@
 export buildconfig
 export color
 export gpu_data
+export imagetypes
 export matrix
 export vector
 export utils
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/semicongine/core/imagetypes.nim	Tue May 09 19:52:57 2023 +0700
@@ -0,0 +1,16 @@
+type
+  Pixel* = array[4, uint8]
+  ImageObject* = object
+    width*: uint32
+    height*: uint32
+    imagedata*: seq[Pixel]
+  Image* = ref ImageObject
+
+proc newImage*(width, height: uint32, imagedata: seq[Pixel] = @[]): Image =
+  assert width > 0 and height > 0
+  result.imagedata = (if imagedata.len == 0: newSeq[Pixel](width * height) else: imagedata)
+  assert width * height == uint32(result.imagedata.len)
+
+  result = new Image
+  result.width = width
+  result.height = height
--- a/src/semicongine/engine.nim	Tue May 09 18:19:17 2023 +0700
+++ b/src/semicongine/engine.nim	Tue May 09 19:52:57 2023 +0700
@@ -82,8 +82,8 @@
     enabledLayers.add "VK_LAYER_KHRONOS_validation"
     putEnv("VK_LAYER_ENABLES", "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT")
 
-    if defined(linux):
-      enabledLayers.add "VK_LAYER_MESA_overlay"
+  if defined(linux):
+    enabledLayers.add "VK_LAYER_MESA_overlay"
   result.instance = result.window.createInstance(
     vulkanVersion=VK_MAKE_API_VERSION(0, 1, 3, 0),
     instanceExtensions=instanceExtensions,
--- a/src/semicongine/entity.nim	Tue May 09 18:19:17 2023 +0700
+++ b/src/semicongine/entity.nim	Tue May 09 19:52:57 2023 +0700
@@ -13,7 +13,7 @@
     name*: string
     root*: Entity
     shaderGlobals*: Table[string, DataValue]
-    textures*: Table[string, seq[TextureImage]]
+    textures*: Table[string, (seq[Image], VkFilter)]
 
   Entity* = ref object of RootObj
     name*: string
@@ -22,13 +22,6 @@
     children*: seq[Entity]
     components*: seq[Component]
 
-  Pixel* = array[4, uint8]
-  TextureImage* = ref object of RootObj
-    width*: uint32
-    height*: uint32
-    imagedata*: seq[Pixel]
-    interpolation*: VkFilter
-
 func addShaderGlobal*[T](scene: var Scene, name: string, data: T) =
   var value = DataValue(thetype: getDataType[T]())
   value.setValue(data)
@@ -40,11 +33,11 @@
 func setShaderGlobal*[T](scene: var Scene, name: string, value: T) =
   setValue[T](scene.shaderGlobals[name], value)
 
-func addTextures*(scene: var Scene, name: string, texture: seq[TextureImage]) =
-  scene.textures[name] = texture
+func addTextures*(scene: var Scene, name: string, texture: seq[Image], interpolation=VK_FILTER_LINEAR) =
+  scene.textures[name] = (texture, interpolation)
 
-func addTexture*(scene: var Scene, name: string, texture: TextureImage) =
-  scene.textures[name] = @[texture]
+func addTexture*(scene: var Scene, name: string, texture: Image, interpolation=VK_FILTER_LINEAR) =
+  scene.textures[name] = (@[texture], interpolation)
 
 func newScene*(name: string, root: Entity): Scene =
   Scene(name: name, root: root)
--- a/src/semicongine/renderer.nim	Tue May 09 18:19:17 2023 +0700
+++ b/src/semicongine/renderer.nim	Tue May 09 19:52:57 2023 +0700
@@ -24,7 +24,6 @@
     vertexBuffers*: Table[MemoryPerformanceHint, Buffer]
     indexBuffer*: Buffer
     uniformBuffers*: seq[Buffer] # one per frame-in-flight
-    images*: seq[Image] # used to back texturees
     textures*: Table[string, seq[Texture]] # per frame-in-flight
     attributeLocation*: Table[string, MemoryPerformanceHint]
     attributeBindingNumber*: Table[string, int]
@@ -172,8 +171,9 @@
 
       for name, images in scene.textures.pairs:
         data.textures[name] = @[]
-        for image in images:
-          data.textures[name].add renderer.device.createTexture(image.width, image.height, 4, addr image.imagedata[0][0], image.interpolation)
+        let interpolation = images[1]
+        for image in images[0]:
+          data.textures[name].add renderer.device.createTexture(image.width, image.height, 4, addr image.imagedata[0][0], interpolation)
       pipeline.setupDescriptors(data.uniformBuffers, data.textures, inFlightFrames=renderer.swapchain.inFlightFrames)
       for frame_i in 0 ..< renderer.swapchain.inFlightFrames:
         pipeline.descriptorSets[frame_i].writeDescriptorSet()
--- a/src/semicongine/vulkan/image.nim	Tue May 09 18:19:17 2023 +0700
+++ b/src/semicongine/vulkan/image.nim	Tue May 09 19:52:57 2023 +0700
@@ -10,7 +10,7 @@
 
 type
   PixelDepth = 1'u32 .. 4'u32
-  Image* = object
+  GPUImage* = object
     device*: Device
     vk*: VkImage
     width*: uint32 # pixel
@@ -27,9 +27,9 @@
     vk*: VkSampler
   ImageView* = object
     vk*: VkImageView
-    image*: Image
+    image*: GPUImage
   Texture* = object
-    image*: Image
+    image*: GPUImage
     imageView*: ImageView
     sampler*: Sampler
 
@@ -41,7 +41,7 @@
 }.toTable
 
 
-proc requirements(image: Image): MemoryRequirements =
+proc requirements(image: GPUImage): MemoryRequirements =
   assert image.vk.valid
   assert image.device.vk.valid
   var req: VkMemoryRequirements
@@ -53,7 +53,7 @@
     if ((req.memoryTypeBits shr i) and 1) == 1:
       result.memoryTypes.add memorytypes[i]
 
-proc allocateMemory(image: var Image, requireMappable: bool, preferVRAM: bool, preferAutoFlush: bool) =
+proc allocateMemory(image: var GPUImage, requireMappable: bool, preferVRAM: bool, preferAutoFlush: bool) =
   assert image.device.vk.valid
   assert image.memoryAllocated == false
 
@@ -68,7 +68,7 @@
   image.memory = image.device.allocate(requirements.size, memoryType)
   checkVkResult image.device.vk.vkBindImageMemory(image.vk, image.memory.vk, VkDeviceSize(0))
 
-proc transitionImageLayout*(image: Image, oldLayout, newLayout: VkImageLayout) =
+proc transitionImageLayout*(image: GPUImage, oldLayout, newLayout: VkImageLayout) =
   var barrier = VkImageMemoryBarrier(
     sType: VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
     oldLayout: oldLayout,
@@ -109,7 +109,7 @@
       1, addr barrier
     )
 
-proc copy*(src: Buffer, dst: Image) =
+proc copy*(src: Buffer, dst: GPUImage) =
   assert src.device.vk.valid
   assert dst.device.vk.valid
   assert src.device == dst.device
@@ -139,7 +139,7 @@
     )
 
 # currently only usable for texture access from shader
-proc createImage*(device: Device, width, height: uint32, depth: PixelDepth, data: pointer): Image =
+proc createImage*(device: Device, width, height: uint32, depth: PixelDepth, data: pointer): GPUImage =
   assert device.vk.valid
   assert width > 0
   assert height > 0
@@ -177,7 +177,7 @@
   result.transitionImageLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
   stagingBuffer.destroy()
 
-proc destroy*(image: var Image) =
+proc destroy*(image: var GPUImage) =
   assert image.device.vk.valid
   assert image.vk.valid
   image.device.vk.vkDestroyImage(image.vk, nil)
@@ -217,7 +217,7 @@
   sampler.vk.reset
 
 proc createImageView*(
-  image: Image,
+  image: GPUImage,
   imageviewtype=VK_IMAGE_VIEW_TYPE_2D,
   baseMipLevel=0'u32,
   levelCount=1'u32,
--- a/src/semicongine/vulkan/renderpass.nim	Tue May 09 18:19:17 2023 +0700
+++ b/src/semicongine/vulkan/renderpass.nim	Tue May 09 19:52:57 2023 +0700
@@ -1,5 +1,4 @@
 import std/options
-import std/logging
 
 import ../core
 import ./device
--- a/src/semicongine/vulkan/swapchain.nim	Tue May 09 18:19:17 2023 +0700
+++ b/src/semicongine/vulkan/swapchain.nim	Tue May 09 19:52:57 2023 +0700
@@ -112,7 +112,7 @@
     var images = newSeq[VkImage](nImages)
     checkVkResult device.vk.vkGetSwapchainImagesKHR(swapChain.vk, addr(nImages), images.toCPointer)
     for vkimage in images:
-      let image = Image(vk: vkimage, format: surfaceFormat.format, device: device)
+      let image = GPUImage(vk: vkimage, format: surfaceFormat.format, device: device)
       let imageview = image.createImageView()
       swapChain.imageviews.add imageview
       swapChain.framebuffers.add swapchain.device.createFramebuffer(renderPass, [imageview], swapchain.dimension)
--- a/tests/test_materials.nim	Tue May 09 18:19:17 2023 +0700
+++ b/tests/test_materials.nim	Tue May 09 19:52:57 2023 +0700
@@ -7,21 +7,21 @@
   let (R, W) = ([255'u8, 0'u8, 0'u8, 255'u8], [255'u8, 255'u8, 255'u8, 255'u8])
   let (RT, WT, PT) = (hexToColorAlpha("A51931").asPixel, hexToColorAlpha("F4F5F8").asPixel, hexToColorAlpha("2D2A4A").asPixel)
   let
-    t1 = TextureImage(width: 5, height: 5, imagedata: @[
+    t1 = Image(width: 5, height: 5, imagedata: @[
       R, R, R, R, R,
       R, R, W, R, R,
       R, W, W, W, R,
       R, R, W, R, R,
       R, R, R, R, R,
     ])
-    t2 = TextureImage(width: 7, height: 5, imagedata: @[
+    t2 = Image(width: 7, height: 5, imagedata: @[
       RT, RT, RT, RT, RT, RT, RT,
       WT, WT, WT, WT, WT, WT, WT,
       PT, PT, PT, PT, PT, PT, PT,
       WT, WT, WT, WT, WT, WT, WT,
       RT, RT, RT, RT, RT, RT, RT,
     ])
-  scene.addTextures("my_texture", @[t1, t2])
+  scene.addTextures("my_texture", @[t1, t2], interpolation=VK_FILTER_NEAREST)
   scene.addShaderGlobal("time", 0'f32)
   var m: Mesh = Mesh(scene.root.components[0])
 
--- a/tests/test_vulkan_wrapper.nim	Tue May 09 18:19:17 2023 +0700
+++ b/tests/test_vulkan_wrapper.nim	Tue May 09 19:52:57 2023 +0700
@@ -37,31 +37,31 @@
   result = newEntity("root",
     newEntity("triangle1", newMesh(
       positions=[newVec3f(0.0, -0.5), newVec3f(0.5, 0.5), newVec3f(-0.5, 0.5)],
-      colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)],
+      colors=[newVec4f(1.0, 0.0, 0.0, 1), newVec4f(0.0, 1.0, 0.0, 1), newVec4f(0.0, 0.0, 1.0, 1)],
     )),
     newEntity("triangle1b", newMesh(
       positions=[newVec3f(0.0, -0.4), newVec3f(0.4, 0.4), newVec3f(-0.4, 0.5)],
-      colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)],
+      colors=[newVec4f(1.0, 0.0, 0.0, 1), newVec4f(0.0, 1.0, 0.0, 1), newVec4f(0.0, 0.0, 1.0, 1)],
     )),
     newEntity("triangle2a", newMesh(
       positions=[newVec3f(0.0, 0.5), newVec3f(0.5, -0.5), newVec3f(-0.5, -0.5)],
-      colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)],
+      colors=[newVec4f(1.0, 0.0, 0.0, 1), newVec4f(0.0, 1.0, 0.0, 1), newVec4f(0.0, 0.0, 1.0, 1)],
       indices=[[0'u16, 2'u16, 1'u16]]
     )),
     newEntity("triangle2b", newMesh(
       positions=[newVec3f(0.0, 0.4), newVec3f(0.4, -0.4), newVec3f(-0.4, -0.4)],
-      colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)],
+      colors=[newVec4f(1.0, 0.0, 0.0, 1), newVec4f(0.0, 1.0, 0.0, 1), newVec4f(0.0, 0.0, 1.0, 1)],
       indices=[[0'u16, 2'u16, 1'u16]]
     )),
     newEntity("triangle3a", newMesh(
       positions=[newVec3f(0.4, 0.5), newVec3f(0.9, -0.3), newVec3f(0.0, -0.3)],
-      colors=[newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0)],
+      colors=[newVec4f(1.0, 1.0, 0.0, 1), newVec4f(1.0, 1.0, 0.0, 1), newVec4f(1.0, 1.0, 0.0, 1)],
       indices=[[0'u32, 2'u32, 1'u32]],
       autoResize=false
     )),
     newEntity("triangle3b", newMesh(
       positions=[newVec3f(0.4, 0.5), newVec3f(0.9, -0.3), newVec3f(0.0, -0.3)],
-      colors=[newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0)],
+      colors=[newVec4f(1.0, 1.0, 0.0, 1), newVec4f(1.0, 1.0, 0.0, 1), newVec4f(1.0, 1.0, 0.0, 1)],
       indices=[[0'u32, 2'u32, 1'u32]],
       autoResize=false
     )),
@@ -72,21 +72,21 @@
 proc scene_simple(): Entity =
   var mymesh1 = newMesh(
     positions=[newVec3f(0.0, -0.3), newVec3f(0.3, 0.3), newVec3f(-0.3, 0.3)],
-    colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)],
+    colors=[newVec4f(1.0, 0.0, 0.0, 1), newVec4f(0.0, 1.0, 0.0, 1), newVec4f(0.0, 0.0, 1.0, 1)],
   )
   var mymesh2 = newMesh(
     positions=[newVec3f(0.0, -0.5), newVec3f(0.5, 0.5), newVec3f(-0.5, 0.5)],
-    colors=[newVec3f(1.0, 0.0, 0.0), newVec3f(0.0, 1.0, 0.0), newVec3f(0.0, 0.0, 1.0)],
+    colors=[newVec4f(1.0, 0.0, 0.0, 1), newVec4f(0.0, 1.0, 0.0, 1), newVec4f(0.0, 0.0, 1.0, 1)],
   )
   var mymesh3 = newMesh(
     positions=[newVec3f(0.0, -0.6), newVec3f(0.6, 0.6), newVec3f(-0.6, 0.6)],
-    colors=[newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0), newVec3f(1.0, 1.0, 0.0)],
+    colors=[newVec4f(1.0, 1.0, 0.0, 1), newVec4f(1.0, 1.0, 0.0, 1), newVec4f(1.0, 1.0, 0.0, 1)],
     indices=[[0'u32, 1'u32, 2'u32]],
     autoResize=false
   )
   var mymesh4 = newMesh(
     positions=[newVec3f(0.0, -0.8), newVec3f(0.8, 0.8), newVec3f(-0.8, 0.8)],
-    colors=[newVec3f(0.0, 0.0, 1.0), newVec3f(0.0, 0.0, 1.0), newVec3f(0.0, 0.0, 1.0)],
+    colors=[newVec4f(0.0, 0.0, 1.0, 1), newVec4f(0.0, 0.0, 1.0, 1), newVec4f(0.0, 0.0, 1.0, 1)],
     indices=[[0'u16, 1'u16, 2'u16]],
     instanceCount=2
   )
@@ -107,7 +107,7 @@
 
 proc scene_flag(): Entity =
   var r = rect(color="ff0000")
-  r.updateMeshData("color", @[newVec3f(0, 0), newVec3f(1, 0), newVec3f(1, 1), newVec3f(0, 1)])
+  r.updateMeshData("color", @[newVec4f(0, 0), newVec4f(1, 0), newVec4f(1, 1), newVec4f(0, 1)])
   result = newEntity("root", r)
 
 proc main() =
@@ -117,10 +117,10 @@
   const
     vertexInput = @[
       attr[Vec3f]("position", memoryPerformanceHint=PreferFastRead),
-      attr[Vec3f]("color", memoryPerformanceHint=PreferFastWrite),
+      attr[Vec4f]("color", memoryPerformanceHint=PreferFastWrite),
       attr[Vec3f]("translate", perInstance=true)
     ]
-    vertexOutput = @[attr[Vec3f]("outcolor")]
+    vertexOutput = @[attr[Vec4f]("outcolor")]
     uniforms = @[attr[float32]("time")]
     samplers = @[attr[Sampler2DType]("my_little_texture")]
     fragOutput = @[attr[Vec4f]("color")]
@@ -138,7 +138,7 @@
       uniforms=uniforms,
       samplers=samplers,
       outputs=fragOutput,
-      main="color = texture(my_little_texture, outcolor.xy) * 0.5 + vec4(outcolor, 1) * 0.5;"
+      main="color = texture(my_little_texture, outcolor.xy) * 0.5 + outcolor * 0.5;"
     )
   var renderPass = engine.gpuDevice.simpleForwardRenderPass(vertexCode, fragmentCode)
   engine.setRenderer(renderPass)
@@ -153,13 +153,13 @@
   for scene in scenes.mitems:
     scene.addShaderGlobal("time", 0.0'f32)
     let (R, W) = ([255'u8, 0'u8, 0'u8, 255'u8], [255'u8, 255'u8, 255'u8, 255'u8])
-    scene.addTexture("my_little_texture", TextureImage(width: 5, height: 5, imagedata: @[
+    scene.addTexture("my_little_texture", Image(width: 5, height: 5, imagedata: @[
       R, R, R, R, R,
       R, R, W, R, R,
       R, W, W, W, R,
       R, R, W, R, R,
       R, R, R, R, R,
-    ]))
+    ]), VK_FILTER_NEAREST)
     engine.addScene(scene, vertexInput)
 
   # MAINLOOP