changeset 308:c73224f9d38f

add: some API improvments for vector, entity, and some other stuff
author Sam <sam@basx.dev>
date Sat, 08 Jul 2023 18:52:34 +0700
parents f471426ef8e2
children 81949dafd8f4
files src/semicongine/core/vector.nim src/semicongine/engine.nim src/semicongine/renderer.nim src/semicongine/scene.nim src/semicongine/settings.nim src/semicongine/vulkan/drawable.nim src/semicongine/vulkan/framebuffer.nim tests/test_vector.nim
diffstat 8 files changed, 106 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/core/vector.nim	Wed Jun 28 00:36:57 2023 +0700
+++ b/src/semicongine/core/vector.nim	Sat Jul 08 18:52:34 2023 +0700
@@ -15,9 +15,12 @@
   Vec2f* = TVec2[float32]
   Vec3f* = TVec3[float32]
   Vec4f* = TVec4[float32]
-  Vec2i* = TVec2[uint32]
-  Vec3i* = TVec3[uint32]
-  Vec4i* = TVec4[uint32]
+  Vec2i* = TVec2[int32]
+  Vec3i* = TVec3[int32]
+  Vec4i* = TVec4[int32]
+  Vec2u* = TVec2[uint32]
+  Vec3u* = TVec3[uint32]
+  Vec4u* = TVec4[uint32]
 
 converter toVec2*[T: SomeNumber](orig: TVec3[T]|TVec4[T]): TVec2[T] =
   TVec2[T]([orig[0], orig[1]])
@@ -46,6 +49,18 @@
   Vec3f([x, y, z])
 func newVec4f*(x=0'f32, y=0'f32, z=0'f32, a=0'f32): auto =
   Vec4f([x, y, z, a])
+func newVec2i*(x=0'i32, y=0'i32): auto =
+  Vec2i([x, y])
+func newVec3i*(x=0'i32, y=0'i32, z=0'i32): auto =
+  Vec3i([x, y, z])
+func newVec4i*(x=0'i32, y=0'i32, z=0'i32, a=0'i32): auto =
+  Vec4i([x, y, z, a])
+func newVec2u*(x=0'u32, y=0'u32): auto =
+  Vec2u([x, y])
+func newVec3u*(x=0'u32, y=0'u32, z=0'u32): auto =
+  Vec3u([x, y, z])
+func newVec4u*(x=0'u32, y=0'u32, z=0'u32, a=0'u32): auto =
+  Vec4u([x, y, z, a])
 
 # generates constants: Xf, Xf32, Xf64, Xi, Xi8, Xi16, Xi32, Xi64
 # Also for Y, Z, R, G, B and One
@@ -105,25 +120,18 @@
 func length*(vec: TVec4[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[
     1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3]))
 
-func normalized*[T](vec: TVec2[T]): auto =
+func normalized*[T: SomeFloat](vec: TVec2[T]): auto =
   let l = vec.length
-  when T is SomeFloat:
-    TVec2[T]([vec[0] / l, vec[1] / l])
-  else:
-    TVec2[float]([float(vec[0]) / l, float(vec[1]) / l])
-func normalized*[T](vec: TVec3[T]): auto =
+  if l == 0: vec
+  else: TVec2[T]([vec[0] / l, vec[1] / l])
+func normalized*[T: SomeFloat](vec: TVec3[T]): auto =
   let l = vec.length
-  when T is SomeFloat:
-    TVec3[T]([vec[0] / l, vec[1] / l, vec[2] / l])
-  else:
-    TVec3[float]([float(vec[0]) / l, float(vec[1]) / l, float(vec[2]) / l])
-func normalized*[T](vec: TVec4[T]): auto =
+  if l == 0: return vec
+  else: TVec3[T]([vec[0] / l, vec[1] / l, vec[2] / l])
+func normalized*[T: SomeFloat](vec: TVec4[T]): auto =
   let l = vec.length
-  when T is SomeFloat:
-    TVec4[T]([vec[0] / l, vec[1] / l, vec[2] / l, vec[3] / l])
-  else:
-    TVec4[float]([float(vec[0]) / l, float(vec[1]) / l, float(vec[2]) / l,
-        float(vec[3]) / l])
+  if l == 0: return vec
+  else: TVec4[T]([vec[0] / l, vec[1] / l, vec[2] / l, vec[3] / l])
 
 # scalar operations
 func `+`*(a: TVec2, b: SomeNumber): auto = TVec2([a[0] + b, a[1] + b])
@@ -222,7 +230,7 @@
 # macro to allow creation of new vectors by specifying vector components as attributes
 # e.g. myVec.xxy will return a new Vec3 that contains the components x, x an y of the original vector
 # (instead of x, y, z for a simple copy)
-proc vectorAttributeAccessor(accessor: string): NimNode =
+proc vectorAttributeAccessor(accessor: string): seq[NimNode] =
   const ACCESSOR_INDICES = {
     'x': 0,
     'y': 1,
@@ -233,28 +241,55 @@
     'b': 2,
     'a': 3,
   }.toTable
-  var ret: NimNode
+  var getterCode, setterCode: NimNode
   let accessorvalue = accessor
 
   if accessorvalue.len == 0:
     raise newException(Exception, "empty attribute")
   elif accessorvalue.len == 1:
-    ret = nnkBracketExpr.newTree(ident("value"), newLit(ACCESSOR_INDICES[
-        accessorvalue[0]]))
+    getterCode = nnkBracketExpr.newTree(ident("vec"), newLit(ACCESSOR_INDICES[accessorvalue[0]]))
+    setterCode = nnkStmtList.newTree(
+      nnkAsgn.newTree(
+        nnkBracketExpr.newTree(ident("vec"), newLit(ACCESSOR_INDICES[accessorvalue[0]])), ident("value"))
+    )
   if accessorvalue.len > 1:
     var attrs = nnkBracket.newTree()
     for attrname in accessorvalue:
-      attrs.add(nnkBracketExpr.newTree(ident("value"), newLit(ACCESSOR_INDICES[attrname])))
-    ret = nnkCall.newTree(ident("TVec" & $accessorvalue.len), attrs)
+      attrs.add(nnkBracketExpr.newTree(ident("vec"), newLit(ACCESSOR_INDICES[attrname])))
+    getterCode = nnkCall.newTree(ident("TVec" & $accessorvalue.len), attrs)
+    setterCode = nnkStmtList.newTree()
+    var i = 0
+    for attrname in accessorvalue:
+      setterCode.add nnkAsgn.newTree(
+        nnkBracketExpr.newTree(ident("vec"), newLit(ACCESSOR_INDICES[attrname])),
+        nnkBracketExpr.newTree(ident("value"), newLit(i)),
+      )
+      inc i
 
-  newProc(
+  result.add newProc(
     name = nnkPostfix.newTree(ident("*"), ident(accessor)),
-    params = [ident("auto"), nnkIdentDefs.newTree(ident("value"), ident("TVec"),
-        newEmptyNode())],
-    body = newStmtList(ret),
+    params = [ident("auto"), nnkIdentDefs.newTree(ident("vec"), ident("TVec"), newEmptyNode())],
+    body = newStmtList(getterCode),
     procType = nnkFuncDef,
   )
 
+  result.add nnkFuncDef.newTree(
+    nnkPostfix.newTree(
+      newIdentNode("*"),
+      nnkAccQuoted.newTree(newIdentNode(accessor), newIdentNode("="))
+    ),
+    newEmptyNode(),
+    nnkGenericParams.newTree(nnkIdentDefs.newTree(newIdentNode("T"), newEmptyNode(), newEmptyNode())),
+    nnkFormalParams.newTree(
+      newEmptyNode(),
+      nnkIdentDefs.newTree( newIdentNode("vec"), nnkVarTy.newTree(newIdentNode("TVec")), newEmptyNode()),
+      nnkIdentDefs.newTree( newIdentNode("value"), newIdentNode("T"), newEmptyNode())
+    ),
+    newEmptyNode(),
+    newEmptyNode(),
+    setterCode
+  )
+
 macro createVectorAttribAccessorFuncs() =
   const COORD_ATTRS = ["x", "y", "z", "w"]
   const COLOR_ATTRS = ["r", "g", "b", "a"]
--- a/src/semicongine/engine.nim	Wed Jun 28 00:36:57 2023 +0700
+++ b/src/semicongine/engine.nim	Sat Jul 08 18:52:34 2023 +0700
@@ -82,7 +82,7 @@
     enabledLayers.add "VK_LAYER_KHRONOS_validation"
     putEnv("VK_LAYER_ENABLES", "VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT")
 
-  if defined(linux):
+  if defined(linux) and DEBUG:
     enabledLayers.add "VK_LAYER_MESA_overlay"
   result.instance = result.window.createInstance(
     vulkanVersion=VK_MAKE_API_VERSION(0, 1, 3, 0),
--- a/src/semicongine/renderer.nim	Wed Jun 28 00:36:57 2023 +0700
+++ b/src/semicongine/renderer.nim	Sat Jul 08 18:52:34 2023 +0700
@@ -142,6 +142,7 @@
 
     let indexed = mesh.indexType != MeshIndexType.None
     var drawable = Drawable(
+      mesh: mesh,
       elementCount: if indexed: mesh.indicesCount else: mesh.vertexCount,
       bufferOffsets: offsets,
       instanceCount: mesh.instanceCount,
--- a/src/semicongine/scene.nim	Wed Jun 28 00:36:57 2023 +0700
+++ b/src/semicongine/scene.nim	Sat Jul 08 18:52:34 2023 +0700
@@ -60,6 +60,10 @@
     if component of EntityAnimation and EntityAnimation(component).player.playing:
       result = result * EntityAnimation(component).player.currentValue
 
+# TODO: position-setter
+func position*(entity: Entity): Vec3f =
+  return entity.transform.col(3)
+
 func originalTransform*(entity: Entity): Mat4 =
   entity.internal_transform
 
--- a/src/semicongine/settings.nim	Wed Jun 28 00:36:57 2023 +0700
+++ b/src/semicongine/settings.nim	Sat Jul 08 18:52:34 2023 +0700
@@ -43,36 +43,36 @@
 proc reloadSettings*() =
   allsettings = loadAllConfig()
 
-proc configStr(key, section, namespace: string, default: string): string =
+proc configStr(key, section, namespace: string): string =
   when CONFIGHOTRELOAD:
     while configUpdates.peek() > 0:
       let (updatedNamespace, updatedConfig) = configUpdates.recv()
       allsettings[updatedNamespace] = loadConfig(newStringStream(updatedConfig))
   if not allsettings.hasKey(namespace):
-    return default
-  allsettings[namespace].getSectionValue(section, key, default)
+    raise newException(Exception, &"Settings {namespace}.{section}.{key} was not found")
+  allsettings[namespace].getSectionValue(section, key)
 
-proc setting*[T: int|float|string](key, section, namespace: string, default: T): T =
+proc setting*[T: int|float|string](key, section, namespace: string): T =
   when T is int:
-    let value = configStr(key, section, namespace, $default)
+    let value = configStr(key, section, namespace)
     if parseInt(value, result) == 0:
       raise newException(Exception, &"Unable to parse int from settings {namespace}.{section}.{key}: {value}")
   elif T is float:
-    let value = configStr(key, section, namespace, $default)
+    let value = configStr(key, section, namespace)
     if parseFloat(value, result) == 0:
       raise newException(Exception, &"Unable to parse float from settings {namespace}.{section}.{key}: {value}")
   else:
-    result = configStr(key, section, namespace, default)
+    result = configStr(key, section, namespace)
 
-proc setting*[T: int|float|string](identifier: string, default: T): T =
+proc setting*[T: int|float|string](identifier: string): T =
   # identifier can be in the form:
   # {namespace}.{key}
   # {namespace}.{section}.{key}
   let parts = identifier.rsplit(".")
   if parts.len == 1:
     raise newException(Exception, &"Setting with name {identifier} has no namespace")
-  if parts.len == 2: result = setting[T](parts[1], "", parts[0], default)
-  else: result = setting[T](parts[^1], parts[^2], joinPath(parts[0 .. ^3]), default)
+  if parts.len == 2: result = setting[T](parts[1], "", parts[0])
+  else: result = setting[T](parts[^1], parts[^2], joinPath(parts[0 .. ^3]))
 
 proc hadConfigUpdate*(): bool =
   when CONFIGHOTRELOAD == true:
--- a/src/semicongine/vulkan/drawable.nim	Wed Jun 28 00:36:57 2023 +0700
+++ b/src/semicongine/vulkan/drawable.nim	Sat Jul 08 18:52:34 2023 +0700
@@ -3,10 +3,13 @@
 import std/logging
 
 import ../core
+import ../mesh
+import ../scene
 import ./buffer
 
 type
   Drawable* = object
+    mesh*: Mesh
     elementCount*: uint32 # number of vertices or indices
     bufferOffsets*: seq[(string, MemoryPerformanceHint, uint64)] # list of buffers and list of offset for each attribute in that buffer
     instanceCount*: uint32 # number of instance
@@ -24,6 +27,8 @@
     &"Drawable(elementCount: {drawable.elementCount}, instanceCount: {drawable.instanceCount}, bufferOffsets: {drawable.bufferOffsets})"
 
 proc draw*(commandBuffer: VkCommandBuffer, drawable: Drawable, vertexBuffers: Table[MemoryPerformanceHint, Buffer], indexBuffer: Buffer) =
+    if drawable.mesh.entity.transform == Mat4():
+      return
     debug "Draw ", drawable
 
     var buffers: seq[VkBuffer]
--- a/src/semicongine/vulkan/framebuffer.nim	Wed Jun 28 00:36:57 2023 +0700
+++ b/src/semicongine/vulkan/framebuffer.nim	Sat Jul 08 18:52:34 2023 +0700
@@ -7,9 +7,9 @@
   Framebuffer* = object
     device*: Device
     vk*: VkFramebuffer
-    dimension*: Vec2I
+    dimension*: Vec2u
 
-proc createFramebuffer*(device: Device, renderpass: VkRenderPass, attachments: openArray[ImageView], dimension: Vec2I): Framebuffer =
+proc createFramebuffer*(device: Device, renderpass: VkRenderPass, attachments: openArray[ImageView], dimension: Vec2u): Framebuffer =
   assert device.vk.valid
   assert renderpass.valid
 
--- a/tests/test_vector.nim	Wed Jun 28 00:36:57 2023 +0700
+++ b/tests/test_vector.nim	Sat Jul 08 18:52:34 2023 +0700
@@ -1,13 +1,13 @@
 import random
-import math
 
 import semicongine
 
 
-proc echoInfo(v: TVec) =
+proc echoInfo[T](v: TVec2[T] or TVec3[T] or TVec4[T]) =
   echo v
   echo "  Length: ", v.length
-  echo "  Normlized: ", v.normalized
+  when T is SomeFloat:
+    echo "  Normlized: ", v.normalized
   echo "  negated: ", -v
 
 proc echoAdd[T, U](v1: T, v2: U) =
@@ -144,6 +144,22 @@
   echo "V3I.g: ", randVec3I().g
   echo "V3F.b: ", randVec3F().b
 
+  # test setters
+  var v1 = randVec2I(); v1.x = 1 ; v1.y = 2 ; v1.r = 3 ; v1.g = 4
+  v1.xy = randVec2I() ; v1.yx = randVec2I() ; v1.rg = randVec2I() ; v1.gr = randVec2I()
+  var v2 = randVec2F(); v2.x = 1.0 ; v2.y = 2.0 ; v2.r = 3.0 ; v2.g = 4.0
+  v2.xy = randVec2F() ; v2.yx = randVec2F() ; v2.rg = randVec2F() ; v2.gr = randVec2F()
+
+  var v3 = randVec3I(); v3.x = 1 ; v3.y = 2 ; v3.z = 3 ; v3.r = 4 ; v3.g = 5 ; v3.b = 6
+  v3.xyz = randVec3I() ; v3.rgb = randVec3I()
+  var v4 = randVec3F(); v4.x = 1.0 ; v4.y = 2.0 ; v4.z = 3.0 ; v4.r = 4.0 ; v4.g = 5.0 ; v4.b = 6.0
+  v4.xyz = randVec3F() ; v4.rgb = randVec3F()
+
+  var v5 = randVec4I(); v5.x = 1 ; v5.y = 2 ; v5.z = 3; v5.w = 4 ; v5.r = 5 ; v5.g = 6 ; v5.b = 7 ; v5.a = 8
+  v5.xyzw = randVec4I() ; v5.rgba = randVec4I()
+  var v6 = randVec4F(); v6.x = 1.0 ; v6.y = 2.0 ; v6.z = 3.0 ; v6.w = 4.0 ; v6.r = 5.0 ; v6.g = 6.0 ; v6.b = 7.0 ; v6.a = 8.0
+  v6.xyzw = randVec4F() ; v6.rgba = randVec4F()
+
   echo "V2I.xx: ", randVec2I().xx
   echo "V2I.yx: ", randVec2I().xy
   echo "V2F.xx: ", randVec2F().xx