Mercurial > games > semicongine
view semicongine/core/vector.nim @ 1293:b94b648df33c
add: nicer string output for integer vecs
author | sam <sam@basx.dev> |
---|---|
date | Sun, 04 Aug 2024 20:50:38 +0700 |
parents | 5de466f5f087 |
children | 9ff18be62a1e |
line wrap: on
line source
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] TVec* = TVec1|TVec2|TVec3|TVec4 Vec1f* = TVec1[float32] Vec2f* = TVec2[float32] Vec3f* = TVec3[float32] Vec4f* = TVec4[float32] Vec1i* = TVec1[int32] Vec2i* = TVec2[int32] Vec3i* = TVec3[int32] Vec4i* = TVec4[int32] Vec1u* = TVec1[uint32] Vec2u* = TVec2[uint32] Vec3u* = TVec3[uint32] Vec4u* = TVec4[uint32] converter ToVec1*[T: SomeNumber](orig: TVec3[T]|TVec4[T]): TVec1[T] = TVec1[T]([orig[0]]) converter ToVec2*[T: SomeNumber](orig: TVec3[T]|TVec4[T]): TVec2[T] = TVec2[T]([orig[0], orig[1]]) converter ToVec3*[T: SomeNumber](orig: TVec4[T]): TVec3[T] = TVec3[T]([orig[0], orig[1], orig[2]]) func ToVec4*[T: SomeNumber](orig: TVec3[T], value: T = default(T)): TVec4[T] = TVec4[T]([orig[0], orig[1], orig[2], value]) func ToVec3*[T: SomeNumber](orig: TVec2[T], value: T = default(T)): TVec3[T] = TVec3[T]([orig[0], orig[1], value]) func ToVec2*[T: SomeNumber](orig: TVec1[T], value: T = default(T)): TVec2[T] = TVec2[T]([orig[0], value]) # shortcuts Vec3f func vec1*[T: SomeNumber](x: T): Vec1f = Vec1f([float32(x)]) func vec2*[T, S: SomeNumber](x: T, y: S): Vec2f = Vec2f([float32(x), float32(y)]) func vec2*[T: SomeNumber](x: T): Vec2f = vec2(x, 0) func vec2*(): Vec2f = vec2(0, 0) func vec3*[T, S, U: SomeNumber](x: T, y: S, z: U): Vec3f = Vec3f([float32(x), float32(y), float32(z)]) func vec3*[T, S: SomeNumber](x: T, y: S): Vec3f = vec3(x, y, 0) func vec3*[T: SomeNumber](x: T): Vec3f = vec3(x, 0, 0) func vec3*(): Vec3f = vec3(0, 0, 0) func vec4*[T, S, U, V: SomeNumber](x: T, y: S, z: U, w: V): Vec4f = Vec4f([float32(x), float32(y), float32(z), float32(w)]) func vec4*[T, S, U: SomeNumber](x: T, y: S, z: U): Vec4f = vec4(x, y, z, 0) func vec4*[T, S: SomeNumber](x: T, y: S): Vec4f = vec4(x, y, 0, 0) func vec4*[T: SomeNumber](x: T): Vec4f = vec4(x, 0, 0, 0) func vec4*(): Vec4f = vec4(0, 0, 0, 0) # shortcuts Vec3i func vec1i*[T: SomeInteger](x: T): Vec1i = Vec1i([int32(x)]) func vec2i*[T, S: SomeInteger](x: T, y: S): Vec2i = Vec2i([int32(x), int32(y)]) func vec2i*[T: SomeInteger](x: T): Vec2i = vec2i(x, 0) func vec2i*(): Vec2i = vec2i(0, 0) func vec3i*[T, S, U: SomeInteger](x: T, y: S, z: U): Vec3i = Vec3i([int32(x), int32(y), int32(z)]) func vec3i*[T, S: SomeInteger](x: T, y: S): Vec3i = vec3i(x, y, 0) func vec3i*[T: SomeInteger](x: T): Vec3i = vec3i(x, 0, 0) func vec3i*(): Vec3i = vec3i(0, 0, 0) func vec4i*[T, S, U, V: SomeInteger](x: T, y: S, z: U, w: V): Vec4i = Vec4i([int32(x), int32(y), int32(z), int32(w)]) func vec4i*[T, S, U: SomeInteger](x: T, y: S, z: U): Vec4i = vec4i(x, y, z, 0) func vec4i*[T, S: SomeInteger](x: T, y: S): Vec4i = vec4i(x, y, 0, 0) func vec4i*[T: SomeInteger](x: T): Vec4i = vec4i(x, 0, 0, 0) func vec4i*(): Vec4i = vec4i(0, 0, 0, 0) # shortcuts color func toVec*(value: string): Vec4f = assert value != "" var hex = value if hex[0] == '#': hex = hex[1 .. ^1] # when 3 or 6 -> set alpha to 1.0 assert hex.len == 3 or hex.len == 6 or hex.len == 4 or hex.len == 8 if hex.len == 3: hex = hex & "f" if hex.len == 4: hex = hex[0] & hex[0] & hex[1] & hex[1] & hex[2] & hex[2] & hex[3] & hex[3] if hex.len == 6: hex = hex & "ff" assert hex.len == 8 let r = parseHexInt(hex[0 .. 1]).float32 / 255'f32 g = parseHexInt(hex[2 .. 3]).float32 / 255'f32 b = parseHexInt(hex[4 .. 5]).float32 / 255'f32 a = parseHexInt(hex[6 .. 7]).float32 / 255'f32 return vec4(r, g, b, a) const X* = vec3(1, 0, 0) Y* = vec3(0, 1, 0) Z* = vec3(0, 0, 1) R* = vec4(1, 0, 0, 1) G* = vec4(1, 0, 0, 1) B* = vec4(1, 0, 0, 1) func to*[T](v: TVec1): auto = TVec1([T(v[0])]) func to*[T](v: TVec2): auto = TVec2([T(v[0]), T(v[1])]) func to*[T](v: TVec3): auto = TVec3([T(v[0]), T(v[1]), T(v[2])]) func to*[T](v: TVec4): auto = TVec4([T(v[0]), T(v[1]), T(v[2]), T(v[3])]) func toVecString[T: TVec](value: T): string = var items: seq[string] for item in value: when elementType(value) is SomeFloat: items.add(&"{item:.5f}") else: items.add(&"{item}") & "(" & join(items, " ") & ")" func `$`*(v: TVec1[SomeNumber]): string = toVecString[TVec1[SomeNumber]](v) func `$`*(v: TVec2[SomeNumber]): string = toVecString[TVec2[SomeNumber]](v) func `$`*(v: TVec3[SomeNumber]): string = toVecString[TVec3[SomeNumber]](v) func `$`*(v: TVec4[SomeNumber]): string = toVecString[TVec4[SomeNumber]](v) func length*(vec: TVec1): auto = vec[0] func length*(vec: TVec2[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1]) func length*(vec: TVec2[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1])) func length*(vec: TVec3[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]) func length*(vec: TVec3[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2])) func length*(vec: TVec4[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3]) 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 normal*[T: SomeFloat](vec: TVec2[T]): auto = TVec2[T]([vec[1], -vec[0]]) func normalized*[T: SomeFloat](vec: TVec1[T]): auto = return T(1) func normalized*[T: SomeFloat](vec: TVec2[T]): auto = let l = vec.length 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 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 if l == 0: return vec else: TVec4[T]([vec[0] / l, vec[1] / l, vec[2] / l, vec[3] / l]) # scalar operations func `+`*(a: TVec1, b: SomeNumber): auto = TVec1([a[0] + b]) func `+`*(a: TVec2, b: SomeNumber): auto = TVec2([a[0] + b, a[1] + b]) func `+`*(a: TVec3, b: SomeNumber): auto = TVec3([a[0] + b, a[1] + b, a[2] + b]) func `+`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] + b, a[1] + b, a[2] + b, a[3] + b]) func `-`*(a: TVec1, b: SomeNumber): auto = TVec1([a[0] - b]) func `-`*(a: TVec2, b: SomeNumber): auto = TVec2([a[0] - b, a[1] - b]) func `-`*(a: TVec3, b: SomeNumber): auto = TVec3([a[0] - b, a[1] - b, a[2] - b]) func `-`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] - b, a[1] - b, a[2] - b, a[3] - b]) func `*`*(a: TVec1, b: SomeNumber): auto = TVec1([a[0] * b]) func `*`*(a: TVec2, b: SomeNumber): auto = TVec2([a[0] * b, a[1] * b]) func `*`*(a: TVec3, b: SomeNumber): auto = TVec3([a[0] * b, a[1] * b, a[2] * b]) func `*`*(a: TVec4, b: SomeNumber): auto = TVec4([a[0] * b, a[1] * b, a[2] * b, a[3] * b]) func `/`*[T: SomeInteger](a: TVec1[T], b: SomeInteger): auto = TVec1([a[0] div b]) func `/`*[T: SomeFloat](a: TVec1[T], b: SomeFloat): auto = TVec1([a[0] / b]) func `/`*[T: SomeInteger](a: TVec2[T], b: SomeInteger): auto = TVec2([a[0] div b, a[1] div b]) func `/`*[T: SomeFloat](a: TVec2[T], b: SomeFloat): auto = TVec2([a[0] / b, a[1] / b]) func `/`*[T: SomeInteger](a: TVec3[T], b: SomeInteger): auto = TVec3([a[0] div b, a[1] div b, a[2] div b]) func `/`*[T: SomeFloat](a: TVec3[T], b: SomeFloat): auto = TVec3([a[0] / b, a[1] / b, a[2] / b]) func `/`*[T: SomeInteger](a: TVec4[T], b: SomeInteger): auto = TVec4([a[0] div b, a[1] div b, a[2] div b, a[3] div b]) func `/`*[T: SomeFloat](a: TVec4[T], b: SomeFloat): auto = TVec4([a[0] / b, a[1] / b, a[2] / b, a[3] / b]) func `+`*(a: SomeNumber, b: TVec1): auto = TVec1([a + b[0]]) func `+`*(a: SomeNumber, b: TVec2): auto = TVec2([a + b[0], a + b[1]]) func `+`*(a: SomeNumber, b: TVec3): auto = TVec3([a + b[0], a + b[1], a + b[2]]) func `+`*(a: SomeNumber, b: TVec4): auto = TVec4([a + b[0], a + b[1], a + b[2], a + b[3]]) func `-`*(a: SomeNumber, b: TVec1): auto = TVec1([a - b[0]]) func `-`*(a: SomeNumber, b: TVec2): auto = TVec2([a - b[0], a - b[1]]) func `-`*(a: SomeNumber, b: TVec3): auto = TVec3([a - b[0], a - b[1], a - b[2]]) func `-`*(a: SomeNumber, b: TVec4): auto = TVec4([a - b[0], a - b[1], a - b[2], a - b[3]]) func `*`*(a: SomeNumber, b: TVec1): auto = TVec1([a * b[0]]) func `*`*(a: SomeNumber, b: TVec2): auto = TVec2([a * b[0], a * b[1]]) func `*`*(a: SomeNumber, b: TVec3): auto = TVec3([a * b[0], a * b[1], a * b[2]]) func `*`*(a: SomeNumber, b: TVec4): auto = TVec4([a * b[0], a * b[1], a * b[2], a * b[3]]) func `/`*[T: SomeInteger](a: SomeInteger, b: TVec1[T]): auto = TVec1([a div b[0]]) func `/`*[T: SomeFloat](a: SomeFloat, b: TVec1[T]): auto = TVec1([a / b[0]]) func `/`*[T: SomeInteger](a: SomeInteger, b: TVec2[T]): auto = TVec2([a div b[0], a div b[1]]) func `/`*[T: SomeFloat](a: SomeFloat, b: TVec2[T]): auto = TVec2([a / b[0], a / b[1]]) func `/`*[T: SomeInteger](a: SomeInteger, b: TVec3[T]): auto = TVec3([a div b[0], a div b[1], a div b[2]]) func `/`*[T: SomeFloat](a: SomeFloat, b: TVec3[T]): auto = TVec3([a / b[0], a / b[1], a / b[2]]) func `/`*[T: SomeInteger](a: SomeInteger, b: TVec4[T]): auto = TVec4([a div b[ 0], a div b[1], a div b[2], a div b[3]]) func `/`*[T: SomeFloat](a: SomeFloat, b: TVec4[T]): auto = TVec4([a / b[0], a / b[1], a / b[2], a / b[3]]) # compontent-wise operations func `+`*(a, b: TVec1): auto = TVec1([a[0] + b[0]]) func `+`*(a, b: TVec2): auto = TVec2([a[0] + b[0], a[1] + b[1]]) func `+`*(a, b: TVec3): auto = TVec3([a[0] + b[0], a[1] + b[1], a[2] + b[2]]) func `+`*(a, b: TVec4): auto = TVec4([a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]]) func `-`*(a: TVec1): auto = TVec1([-a[0]]) func `-`*(a: TVec2): auto = TVec2([-a[0], -a[1]]) func `-`*(a: TVec3): auto = TVec3([-a[0], -a[1], -a[2]]) func `-`*(a: TVec4): auto = TVec4([-a[0], -a[1], -a[2], -a[3]]) func `-`*(a, b: TVec1): auto = TVec1([a[0] - b[0]]) func `-`*(a, b: TVec2): auto = TVec2([a[0] - b[0], a[1] - b[1]]) func `-`*(a, b: TVec3): auto = TVec3([a[0] - b[0], a[1] - b[1], a[2] - b[2]]) func `-`*(a, b: TVec4): auto = TVec4([a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]]) func `*`*(a, b: TVec1): auto = TVec1([a[0] * b[0]]) func `*`*(a, b: TVec2): auto = TVec2([a[0] * b[0], a[1] * b[1]]) func `*`*(a, b: TVec3): auto = TVec3([a[0] * b[0], a[1] * b[1], a[2] * b[2]]) func `*`*(a, b: TVec4): auto = TVec4([a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]]) func `/`*[T: SomeInteger](a, b: TVec1[T]): auto = TVec1([a[0] div b[0]]) func `/`*[T: SomeFloat](a, b: TVec1[T]): auto = TVec1([a[0] / b[0]]) func `/`*[T: SomeInteger](a, b: TVec2[T]): auto = TVec2([a[0] div b[0], a[1] div b[1]]) func `/`*[T: SomeFloat](a, b: TVec2[T]): auto = TVec2([a[0] / b[0], a[1] / b[1]]) func `/`*[T: SomeInteger](a, b: TVec3[T]): auto = TVec3([a[0] div b[0], a[1] div b[1], a[2] div b[2]]) func `/`*[T: SomeFloat](a, b: TVec3[T]): auto = TVec3([a[0] / b[0], a[1] / b[1], a[2] / b[2]]) func `/`*[T: SomeInteger](a, b: TVec4[T]): auto = TVec4([a[0] div b[0], a[1] div b[1], a[2] div b[2], a[3] div b[3]]) func `/`*[T: SomeFloat](a, b: TVec4[T]): auto = TVec4([a[0] / b[0], a[1] / b[1], a[2] / b[2], a[3] / b[3]]) # assignment operations, scalar func `+=`*(a: var TVec1, b: SomeNumber) = a = a + b func `+=`*(a: var TVec2, b: SomeNumber) = a = a + b func `+=`*(a: var TVec3, b: SomeNumber) = a = a + b func `+=`*(a: var TVec4, b: SomeNumber) = a = a + b func `-=`*(a: var TVec1, b: SomeNumber) = a = a - b func `-=`*(a: var TVec2, b: SomeNumber) = a = a - b func `-=`*(a: var TVec3, b: SomeNumber) = a = a - b func `-=`*(a: var TVec4, b: SomeNumber) = a = a - b func `*=`*(a: var TVec1, b: SomeNumber) = a = a * b func `*=`*(a: var TVec2, b: SomeNumber) = a = a * b func `*=`*(a: var TVec3, b: SomeNumber) = a = a * b func `*=`*(a: var TVec4, b: SomeNumber) = a = a * b func `/=`*(a: var TVec1, b: SomeNumber) = a = a / b func `/=`*(a: var TVec2, b: SomeNumber) = a = a / b func `/=`*(a: var TVec3, b: SomeNumber) = a = a / b func `/=`*(a: var TVec4, b: SomeNumber) = a = a / b # assignment operations, vector func `+=`*(a: var TVec1, b: TVec1) = a = a + b func `+=`*(a: var TVec2, b: TVec2) = a = a + b func `+=`*(a: var TVec3, b: TVec3) = a = a + b func `+=`*(a: var TVec4, b: TVec4) = a = a + b func `-=`*(a: var TVec1, b: TVec1) = a = a - b func `-=`*(a: var TVec2, b: TVec2) = a = a - b func `-=`*(a: var TVec3, b: TVec3) = a = a - b func `-=`*(a: var TVec4, b: TVec4) = a = a - b func `*=`*(a: var TVec1, b: TVec1) = a = a * b func `*=`*(a: var TVec2, b: TVec2) = a = a * b func `*=`*(a: var TVec3, b: TVec3) = a = a * b func `*=`*(a: var TVec4, b: TVec4) = a = a * b func `/=`*(a: var TVec1, b: TVec1) = a = a / b func `/=`*(a: var TVec2, b: TVec2) = a = a / b func `/=`*(a: var TVec3, b: TVec3) = a = a / b func `/=`*(a: var TVec4, b: TVec4) = a = a / b # special operations func pow*(a: TVec1, b: SomeNumber): auto = TVec1([pow(a[0], b)]) func pow*(a: TVec2, b: SomeNumber): auto = TVec2([pow(a[0], b), pow(a[1], b)]) func pow*(a: TVec3, b: SomeNumber): auto = TVec3([pow(a[0], b), pow(a[1], b), pow(a[2], b)]) func pow*(a: TVec4, b: SomeNumber): auto = TVec4([pow(a[0], b), pow(a[1], b), pow(a[2], b), pow(a[3], b)]) func dot*(a, b: TVec1): auto = a[0] * b[0] func dot*(a, b: TVec2): auto = a[0] * b[0] + a[1] * b[1] func dot*(a, b: TVec3): auto = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] func dot*(a, b: TVec4): auto = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3] func cross*(a, b: TVec3): auto = TVec3([ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], ]) # 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): seq[NimNode] = const ACCESSOR_INDICES = { 'x': 0, 'y': 1, 'z': 2, 'w': 3, 'r': 0, 'g': 1, 'b': 2, 'a': 3, }.toTable var getterCode, setterCode: NimNode let accessorvalue = accessor if accessorvalue.len == 0: raise newException(Exception, "empty attribute") elif accessorvalue.len == 1: 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("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 result.add newProc( name = nnkPostfix.newTree(ident("*"), ident(accessor)), 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"] result = nnkStmtList.newTree() for attlist in [COORD_ATTRS, COLOR_ATTRS]: for i in attlist: result.add(vectorAttributeAccessor(i)) for j in attlist: result.add(vectorAttributeAccessor(i & j)) for k in attlist: result.add(vectorAttributeAccessor(i & j & k)) for l in attlist: result.add(vectorAttributeAccessor(i & j & k & l)) createVectorAttribAccessorFuncs() # call e.g. Vec2[int]().randomized() to get a random matrix template makeRandomVectorInit(mattype: typedesc) = proc randomized*[T: SomeInteger](m: mattype[T]): mattype[T] = for i in 0 ..< result.len: result[i] = rand(low(typeof(m[0])) .. high(typeof(m[0]))) proc randomized*[T: SomeFloat](m: mattype[T]): mattype[T] = for i in 0 ..< result.len: result[i] = rand(1.0) makeRandomVectorInit(TVec1) makeRandomVectorInit(TVec2) makeRandomVectorInit(TVec3) makeRandomVectorInit(TVec4) converter Vec2VkExtent*(vec: TVec2[uint32]): VkExtent2D = VkExtent2D(width: vec[0], height: vec[1]) converter Vec3VkExtent*(vec: TVec2[uint32]): VkExtent3D = VkExtent3D(width: vec[0], height: vec[1], depth: vec[2]) func angleBetween*(a, b: Vec3f): float32 = arccos(a.dot(b) / (a.length * b.length))