# HG changeset patch # User Sam # Date 1672202541 -25200 # Node ID d4750f2e076063a43010dda52cdd86e31d1cb4b1 # Parent 04b8471bdab427836a915110c1a6a09021767152 add: vector/matrix modules, tests, nim config script diff -r 04b8471bdab4 -r d4750f2e0760 Makefile --- a/Makefile Tue Dec 27 20:47:48 2022 +0700 +++ b/Makefile Wed Dec 28 11:42:21 2022 +0700 @@ -5,28 +5,42 @@ WINDOWS_DEBUG_OPTIONS := --cc:vcc --passC:'/MDd' --passL:'ucrtd.lib' WINDOWS_RELEASE_OPTIONS := --cc:vcc --passC:'/MD' --passL:'ucrt.lib' -# build -build/debug/linux/hello_triangle: ${SOURCES} - mkdir -p $$( dirname $@ ) +make_dirs: + mkdir -p build/debug/linux + mkdir -p build/release/linux + mkdir -p build/debug/windows + mkdir -p build/release/windows + +# build hello_triangle +build/debug/linux/hello_triangle: ${SOURCES} make_dirs nim c ${COMPILE_OPTIONS} ${DEBUG_OPTIONS} -o:$@ examples/hello_triangle.nim -build/release/linux/hello_triangle: ${SOURCES} - mkdir -p $$( dirname $@ ) +build/release/linux/hello_triangle: ${SOURCES} make_dirs nim c ${COMPILE_OPTIONS} ${RELEASE_OPTIONS} -o:$@ examples/hello_triangle.nim -build/debug/windows/hello_triangle.exe: ${SOURCES} - mkdir -p $$( dirname $@ ) +build/debug/windows/hello_triangle.exe: ${SOURCES} make_dirs nim c ${COMPILE_OPTIONS} ${DEBUG_OPTIONS} ${WINDOWS_DEBUG_OPTIONS} -o:$@ examples/hello_triangle.nim -build/release/windows/hello_triangle.exe: ${SOURCES} - mkdir -p $$( dirname $@ ) +build/release/windows/hello_triangle.exe: ${SOURCES} make_dirs nim c ${COMPILE_OPTIONS} ${RELEASE_OPTIONS} ${WINDOWS_RELEASE_OPTIONS} -o:$@ examples/hello_triangle.nim build_all_linux: build/debug/linux/hello_triangle build/release/linux/hello_triangle build_all_windows: build/debug/windows/hello_triangle.exe build/release/windows/hello_triangle.exe +build_all: build_all_linux build_all_windows -build_all: build_all_linux build_all_windows +# build maths (for testing) +build/debug/linux/maths: ${SOURCES} make_dirs + nim c ${COMPILE_OPTIONS} ${DEBUG_OPTIONS} -o:$@ examples/maths.nim +build/release/linux/maths: ${SOURCES} make_dirs + nim c ${COMPILE_OPTIONS} ${RELEASE_OPTIONS} -o:$@ examples/maths.nim +build/debug/windows/maths.exe: ${SOURCES} make_dirs + nim c ${COMPILE_OPTIONS} ${DEBUG_OPTIONS} ${WINDOWS_DEBUG_OPTIONS} -o:$@ examples/maths.nim +build/release/windows/maths.exe: ${SOURCES} make_dirs + nim c ${COMPILE_OPTIONS} ${RELEASE_OPTIONS} ${WINDOWS_RELEASE_OPTIONS} -o:$@ examples/maths.nim clean: rm -rf build +tests: + testament p tests/ + # publish publish_linux_debug: build/debug/linux/hello_triangle scp $< basx.dev:/var/www/public.basx.dev/joni/linux/debug/ diff -r 04b8471bdab4 -r d4750f2e0760 config.nims --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config.nims Wed Dec 28 11:42:21 2022 +0700 @@ -0,0 +1,1 @@ +switch("path", "src") diff -r 04b8471bdab4 -r d4750f2e0760 src/matrix.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/matrix.nim Wed Dec 28 11:42:21 2022 +0700 @@ -0,0 +1,151 @@ +import random +import std/strutils +import std/typetraits + +import ./vector + +type + # layout is row-first + # having an object instead of directly aliasing the array seems a bit ugly at + # first, but is necessary to be able to work correctly with distinguished + # types (i.e. Mat23 and Mat32 would be an alias for the same type array[6, T] + # which prevents the type system from identifying the correct type at times) + # + # Though, great news is that objects have zero overhead! + Mat22*[T: SomeNumber] = object + data: array[4, T] + Mat23*[T: SomeNumber] = object + data: array[6, T] + Mat32*[T: SomeNumber] = object + data: array[6, T] + Mat33*[T: SomeNumber] = object + data: array[9, T] + Mat34*[T: SomeNumber] = object + data: array[12, T] + Mat43*[T: SomeNumber] = object + data: array[12, T] + Mat44*[T: SomeNumber] = object + data: array[16, T] + MatMM* = Mat22|Mat33|Mat44 + MatMN* = Mat23|Mat32|Mat34|Mat43 + Mat* = MatMM|MatMN + IntegerMat = Mat22[SomeInteger]|Mat33[SomeInteger]|Mat44[SomeInteger]|Mat23[SomeInteger]|Mat32[SomeInteger]|Mat34[SomeInteger]|Mat43[SomeInteger] + FloatMat = Mat22[SomeFloat]|Mat33[SomeFloat]|Mat44[SomeFloat]|Mat23[SomeFloat]|Mat32[SomeFloat]|Mat34[SomeFloat]|Mat43[SomeFloat] + + +func rowCount*(m: Mat22): int = 2 +func columnCount*(m: Mat22): int = 2 +func rowCount*(m: Mat23): int = 2 +func columnCount*(m: Mat23): int = 3 +func rowCount*(m: Mat32): int = 3 +func columnCount*(m: Mat32): int = 2 +func rowCount*(m: Mat33): int = 3 +func columnCount*(m: Mat33): int = 3 +func rowCount*(m: Mat34): int = 3 +func columnCount*(m: Mat34): int = 4 +func rowCount*(m: Mat43): int = 4 +func columnCount*(m: Mat43): int = 3 +func rowCount*(m: Mat44): int = 4 +func columnCount*(m: Mat44): int = 4 + + +func toString[T](value: T): string = + var + strvalues: seq[string] + maxwidth = 0 + + for n in value.data: + let strval = $n + strvalues.add(strval) + if strval.len > maxwidth: + maxwidth = strval.len + + for i in 0 ..< strvalues.len: + let filler = " ".repeat(maxwidth - strvalues[i].len) + if i mod value.columnCount == value.columnCount - 1: + result &= filler & strvalues[i] & "\n" + else: + if i mod value.columnCount == 0: + result &= " " + result &= filler & strvalues[i] & " " + result = $T & "\n" & result + +func `$`*(v: Mat22[SomeNumber]): string = toString[Mat22[SomeNumber]](v) +func `$`*(v: Mat23[SomeNumber]): string = toString[Mat23[SomeNumber]](v) +func `$`*(v: Mat32[SomeNumber]): string = toString[Mat32[SomeNumber]](v) +func `$`*(v: Mat33[SomeNumber]): string = toString[Mat33[SomeNumber]](v) +func `$`*(v: Mat34[SomeNumber]): string = toString[Mat34[SomeNumber]](v) +func `$`*(v: Mat43[SomeNumber]): string = toString[Mat43[SomeNumber]](v) +func `$`*(v: Mat44[SomeNumber]): string = toString[Mat44[SomeNumber]](v) + +func `[]`*[T: Mat](m: T, row, col: int): auto = m.data[col + row * m.columnCount] +proc `[]=`*[T: Mat, U](m: var T, row, col: int, value: U) = m.data[col + row * m.columnCount] = value + +func row*[T: Mat22](m: T, i: 0..1): auto = Vec2([m[i, 0], m[i, 1]]) +func row*[T: Mat32](m: T, i: 0..2): auto = Vec2([m[i, 0], m[i, 1]]) +func row*[T: Mat23](m: T, i: 0..1): auto = Vec3([m[i, 0], m[i, 1], m[i, 2]]) +func row*[T: Mat33](m: T, i: 0..2): auto = Vec3([m[i, 0], m[i, 1], m[i, 2]]) +func row*[T: Mat43](m: T, i: 0..3): auto = Vec3([m[i, 0], m[i, 1], m[i, 2]]) +func row*[T: Mat34](m: T, i: 0..2): auto = Vec4([m[i, 0], m[i, 1], m[i, 2], m[i, 3]]) +func row*[T: Mat44](m: T, i: 0..3): auto = Vec4([m[i, 0], m[i, 1], m[i, 2], m[i, 3]]) + +func col*[T: Mat22](m: T, i: 0..1): auto = Vec2([m[0, i], m[1, i]]) +func col*[T: Mat23](m: T, i: 0..2): auto = Vec2([m[0, i], m[1, i]]) +func col*[T: Mat32](m: T, i: 0..1): auto = Vec3([m[0, i], m[1, i], m[2, i]]) +func col*[T: Mat33](m: T, i: 0..2): auto = Vec3([m[0, i], m[1, i], m[2, i]]) +func col*[T: Mat34](m: T, i: 0..3): auto = Vec3([m[0, i], m[1, i], m[2, i]]) +func col*[T: Mat43](m: T, i: 0..2): auto = Vec4([m[0, i], m[1, i], m[2, i], m[3, i]]) +func col*[T: Mat44](m: T, i: 0..3): auto = Vec4([m[0, i], m[1, i], m[2, i], m[3, i]]) + +func transposed*[T](m: Mat22[T]): Mat22[T] = Mat22[T](data: [ + m[0, 0], m[1, 0], + m[0, 1], m[1, 1], +]) +func transposed*[T](m: Mat23[T]): Mat32[T] = Mat32[T](data: [ + m[0, 0], m[1, 0], + m[0, 1], m[1, 1], + m[0, 2], m[1, 2], +]) +func transposed*[T](m: Mat32[T]): Mat23[T] = Mat23[T](data: [ + m[0, 0], m[1, 0], m[2, 0], + m[0, 1], m[1, 1], m[2, 1], +]) +func transposed*[T](m: Mat33[T]): Mat33[T] = Mat33[T](data: [ + m[0, 0], m[1, 0], m[2, 0], + m[0, 1], m[1, 1], m[2, 1], + m[0, 2], m[1, 2], m[2, 2], +]) +func transposed*[T](m: Mat43[T]): Mat34[T] = Mat34[T](data: [ + m[0, 0], m[1, 0], m[2, 0], m[3, 0], + m[0, 1], m[1, 1], m[2, 1], m[3, 1], + m[0, 2], m[1, 2], m[2, 2], m[3, 2], +]) +func transposed*[T](m: Mat34[T]): Mat43[T] = Mat43[T](data: [ + m[0, 0], m[1, 0], m[2, 0], + m[0, 1], m[1, 1], m[2, 1], + m[0, 2], m[1, 2], m[2, 2], + m[0, 3], m[1, 3], m[2, 3], +]) +func transposed*[T](m: Mat44[T]): Mat44[T] = Mat44[T](data: [ + m[0, 0], m[1, 0], m[2, 0], m[3, 0], + m[0, 1], m[1, 1], m[2, 1], m[3, 1], + m[0, 2], m[1, 2], m[2, 2], m[3, 2], + m[0, 3], m[1, 3], m[2, 3], m[3, 3], +]) + +# call e.g. Mat32[int]().initRandom() to get a random matrix +template makeRandomInit(mattype: typedesc) = + proc randomized*[T: SomeInteger](m: mattype[T]): mattype[T] = + for i in 0 ..< result.data.len: + result.data[i] = rand(low(typeof(m.data[0])) .. high(typeof(m.data[0]))) + proc randomized*[T: SomeFloat](m: mattype[T]): mattype[T] = + for i in 0 ..< result.data.len: + result.data[i] = rand(1.0) + +makeRandomInit(Mat22) +makeRandomInit(Mat23) +makeRandomInit(Mat32) +makeRandomInit(Mat33) +makeRandomInit(Mat34) +makeRandomInit(Mat43) +makeRandomInit(Mat44) diff -r 04b8471bdab4 -r d4750f2e0760 src/vector.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vector.nim Wed Dec 28 11:42:21 2022 +0700 @@ -0,0 +1,203 @@ +import std/math +import std/strutils +import std/macros +import std/typetraits +import std/tables + + +type + Vec2*[T: SomeNumber] = array[2, T] + Vec3*[T: SomeNumber] = array[3, T] + Vec4*[T: SomeNumber] = array[4, T] + Vec* = Vec2|Vec3|Vec4 + +# define some often used constants +func ConstX[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(1), T(0), T(0)]) +func ConstY[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(0), T(1), T(0)]) +func ConstZ[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(0), T(0), T(1)]) +func ConstR[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(1), T(0), T(0)]) +func ConstG[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(0), T(1), T(0)]) +func ConstB[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(0), T(0), T(1)]) + +# generates constants: Xf, Xf32, Xf64, Xi, Xi8, Xi16, Xi32, Xi64 +# Also for Y, Z, R, G, B +# not sure if this is necessary or even a good idea... +macro generateAllConsts() = + result = newStmtList() + for component in ["X", "Y", "Z", "R", "G", "B"]: + for theType in ["int", "int8", "int16", "int32", "int64", "float", "float32", "float64"]: + var typename = theType[0 .. 0] + if theType[^2].isDigit: + typename = typename & theType[^2] + if theType[^1].isDigit: + typename = typename & theType[^1] + result.add( + newConstStmt( + postfix(ident(component & typename), "*"), + newCall(nnkBracketExpr.newTree(ident("Const" & component), ident(theType))) + ) + ) + +generateAllConsts() + +const X* = ConstX[float]() +const Y* = ConstY[float]() +const Z* = ConstZ[float]() + +func newVec2*[T](x, y: T): auto = Vec2([x, y]) +func newVec3*[T](x, y, z: T): auto = Vec3([x, y, z]) +func newVec4*[T](x, y, z, w: T): auto = Vec4([x, y, z, w]) + +func to*[T](v: Vec2): auto = Vec2([T(v[0]), T(v[1])]) +func to*[T](v: Vec3): auto = Vec3([T(v[0]), T(v[1]), T(v[2])]) +func to*[T](v: Vec4): auto = Vec4([T(v[0]), T(v[1]), T(v[2]), T(v[3])]) + +func toString[T](value: T): string = + var items: seq[string] + for item in value: + items.add($item) + $T & "(" & join(items, " ") & ")" + +func `$`*(v: Vec2[SomeNumber]): string = toString[Vec2[SomeNumber]](v) +func `$`*(v: Vec3[SomeNumber]): string = toString[Vec3[SomeNumber]](v) +func `$`*(v: Vec4[SomeNumber]): string = toString[Vec4[SomeNumber]](v) + +func length*(vec: Vec2[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1]) +func length*(vec: Vec2[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1])) +func length*(vec: Vec3[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]) +func length*(vec: Vec3[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2])) +func length*(vec: Vec4[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3]) +func length*(vec: Vec4[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3])) + +func normalized*[T](vec: Vec2[T]): auto = + let l = vec.length + when T is SomeFloat: + Vec2[T]([vec[0] / l, vec[1] / l]) + else: + Vec2[float]([float(vec[0]) / l, float(vec[1]) / l]) +func normalized*[T](vec: Vec3[T]): auto = + let l = vec.length + when T is SomeFloat: + Vec3[T]([vec[0] / l, vec[1] / l, vec[2] / l]) + else: + Vec3[float]([float(vec[0]) / l, float(vec[1]) / l, float(vec[2]) / l]) +func normalized*[T](vec: Vec4[T]): auto = + let l = vec.length + when T is SomeFloat: + Vec4[T]([vec[0] / l, vec[1] / l, vec[2] / l, vec[3] / l]) + else: + Vec4[float]([float(vec[0]) / l, float(vec[1]) / l, float(vec[2]) / l, float(vec[3]) / l]) + +# scalar operations +func `+`*(a: Vec2, b: SomeNumber): auto = Vec2([a[0] + b, a[1] + b]) +func `+`*(a: Vec3, b: SomeNumber): auto = Vec3([a[0] + b, a[1] + b, a[2] + b]) +func `+`*(a: Vec4, b: SomeNumber): auto = Vec4([a[0] + b, a[1] + b, a[2] + b, a[3] + b]) +func `-`*(a: Vec2, b: SomeNumber): auto = Vec2([a[0] - b, a[1] - b]) +func `-`*(a: Vec3, b: SomeNumber): auto = Vec3([a[0] - b, a[1] - b, a[2] - b]) +func `-`*(a: Vec4, b: SomeNumber): auto = Vec4([a[0] - b, a[1] - b, a[2] - b, a[3] - b]) +func `*`*(a: Vec2, b: SomeNumber): auto = Vec2([a[0] * b, a[1] * b]) +func `*`*(a: Vec3, b: SomeNumber): auto = Vec3([a[0] * b, a[1] * b, a[2] * b]) +func `*`*(a: Vec4, b: SomeNumber): auto = Vec4([a[0] * b, a[1] * b, a[2] * b, a[3] * b]) +func `/`*[T: SomeInteger](a: Vec2[T], b: SomeInteger): auto = Vec2([a[0] div b, a[1] div b]) +func `/`*[T: SomeFloat](a: Vec2[T], b: SomeFloat): auto = Vec2([a[0] / b, a[1] / b]) +func `/`*[T: SomeInteger](a: Vec3[T], b: SomeInteger): auto = Vec3([a[0] div b, a[1] div b, a[2] div b]) +func `/`*[T: SomeFloat](a: Vec3[T], b: SomeFloat): auto = Vec3([a[0] / b, a[1] / b, a[2] / b]) +func `/`*[T: SomeInteger](a: Vec4[T], b: SomeInteger): auto = Vec4([a[0] div b, a[1] div b, a[2] div b, a[3] div b]) +func `/`*[T: SomeFloat](a: Vec4[T], b: SomeFloat): auto = Vec4([a[0] / b, a[1] / b, a[2] / b, a[3] / b]) + +func `+`*(a: SomeNumber, b: Vec2): auto = Vec2([a + b[0], a + b[1]]) +func `+`*(a: SomeNumber, b: Vec3): auto = Vec3([a + b[0], a + b[1], a + b[2]]) +func `+`*(a: SomeNumber, b: Vec4): auto = Vec4([a + b[0], a + b[1], a + b[2], a + b[3]]) +func `-`*(a: SomeNumber, b: Vec2): auto = Vec2([a - b[0], a - b[1]]) +func `-`*(a: SomeNumber, b: Vec3): auto = Vec3([a - b[0], a - b[1], a - b[2]]) +func `-`*(a: SomeNumber, b: Vec4): auto = Vec4([a - b[0], a - b[1], a - b[2], a - b[3]]) +func `*`*(a: SomeNumber, b: Vec2): auto = Vec2([a * b[0], a * b[1]]) +func `*`*(a: SomeNumber, b: Vec3): auto = Vec3([a * b[0], a * b[1], a * b[2]]) +func `*`*(a: SomeNumber, b: Vec4): auto = Vec4([a * b[0], a * b[1], a * b[2], a * b[3]]) +func `/`*[T: SomeInteger](a: SomeInteger, b: Vec2[T]): auto = Vec2([a div b[0], a div b[1]]) +func `/`*[T: SomeFloat](a: SomeFloat, b: Vec2[T]): auto = Vec2([a / b[0], a / b[1]]) +func `/`*[T: SomeInteger](a: SomeInteger, b: Vec3[T]): auto = Vec3([a div b[0], a div b[1], a div b[2]]) +func `/`*[T: SomeFloat](a: SomeFloat, b: Vec3[T]): auto = Vec3([a / b[0], a / b[1], a / b[2]]) +func `/`*[T: SomeInteger](a: SomeInteger, b: Vec4[T]): auto = Vec4([a div b[0], a div b[1], a div b[2], a div b[3]]) +func `/`*[T: SomeFloat](a: SomeFloat, b: Vec4[T]): auto = Vec4([a / b[0], a / b[1], a / b[2], a / b[3]]) + +# compontent-wise operations +func `+`*(a, b: Vec2): auto = Vec2([a[0] + b[0], a[1] + b[1]]) +func `+`*(a, b: Vec3): auto = Vec3([a[0] + b[0], a[1] + b[1], a[2] + b[2]]) +func `+`*(a, b: Vec4): auto = Vec4([a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]]) +func `-`*(a: Vec2): auto = Vec2([-a[0], -a[1]]) +func `-`*(a: Vec3): auto = Vec3([-a[0], -a[1], -a[2]]) +func `-`*(a: Vec4): auto = Vec4([-a[0], -a[1], -a[2], -a[3]]) +func `-`*(a, b: Vec2): auto = Vec2([a[0] - b[0], a[1] - b[1]]) +func `-`*(a, b: Vec3): auto = Vec3([a[0] - b[0], a[1] - b[1], a[2] - b[2]]) +func `-`*(a, b: Vec4): auto = Vec4([a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]]) +func `*`*(a, b: Vec2): auto = Vec2([a[0] * b[0], a[1] * b[1]]) +func `*`*(a, b: Vec3): auto = Vec3([a[0] * b[0], a[1] * b[1], a[2] * b[2]]) +func `*`*(a, b: Vec4): auto = Vec4([a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]]) +func `/`*[T: SomeInteger](a, b: Vec2[T]): auto = Vec2([a[0] div b[0], a[1] div b[1]]) +func `/`*[T: SomeFloat](a, b: Vec2[T]): auto = Vec2([a[0] / b[0], a[1] / b[1]]) +func `/`*[T: SomeInteger](a, b: Vec3[T]): auto = Vec3([a[0] div b[0], a[1] div b[1], a[2] div b[2]]) +func `/`*[T: SomeFloat](a, b: Vec3[T]): auto = Vec3([a[0] / b[0], a[1] / b[1], a[2] / b[2]]) +func `/`*[T: SomeInteger](a, b: Vec4[T]): auto = Vec4([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: Vec4[T]): auto = Vec4([a[0] / b[0], a[1] / b[1], a[2] / b[2], a[3] / b[3]]) + +# special operations +func dot*(a, b: Vec2): auto = a[0] * b[0] + a[1] * b[1] +func dot*(a, b: Vec3): auto = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] +func dot*(a, b: Vec4): auto = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3] +func cross*(a, b: Vec3): auto = Vec3([ + 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): NimNode = + const ACCESSOR_INDICES = { + 'x': 0, + 'y': 1, + 'z': 2, + 'w': 3, + 'r': 0, + 'g': 1, + 'b': 2, + 'a': 3, + }.toTable + var ret: NimNode + let accessorvalue = accessor + + if accessorvalue.len == 0: + raise newException(Exception, "empty attribute") + elif accessorvalue.len == 1: + ret = nnkBracket.newTree(ident("value"), newLit(ACCESSOR_INDICES[accessorvalue[0]])) + 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("Vec" & $accessorvalue.len), attrs) + + newProc( + name=nnkPostfix.newTree(ident("*"), ident(accessor)), + params=[ident("auto"), nnkIdentDefs.newTree(ident("value"), ident("Vec"), newEmptyNode())], + body=newStmtList(ret), + procType = nnkFuncDef, + ) + +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() diff -r 04b8471bdab4 -r d4750f2e0760 src/vertex.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vertex.nim Wed Dec 28 11:42:21 2022 +0700 @@ -0,0 +1,5 @@ +type + VertexAttribute = object + + VertexType = object + diff -r 04b8471bdab4 -r d4750f2e0760 tests/megatest.nim diff -r 04b8471bdab4 -r d4750f2e0760 tests/test_matrix.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_matrix.nim Wed Dec 28 11:42:21 2022 +0700 @@ -0,0 +1,255 @@ +import random +import math + +import vector +import matrix + + +proc echoInfo(v: Vec) = + echo v + echo " Length: ", v.length + echo " Normlized: ", v.normalized + echo " negated: ", -v + +proc echoAdd[T, U](v1: T, v2: U) = + echo v1, " + ", v2, " = ", v1 + v2 +proc echoSub[T, U](v1: T, v2: U) = + echo v1, " - ", v2, " = ", v1 - v2 +proc echoMul[T, U](v1: T, v2: U) = + echo v1, " * ", v2, " = ", v1 * v2 +proc echoDiv[T, U](v1: T, v2: U) = + echo v1, " / ", v2, " = ", v1 / v2 +proc echoDot[T, U](v1: T, v2: U) = + echo v1, " o ", v2, " = ", v1.dot(v2) +proc echoCross[T, U](v1: T, v2: U) = + echo v1, " x ", v2, " = ", v1.cross(v2) + +proc randVec2I(): auto = newVec2(rand(1 .. 10), rand(1 .. 10)) +proc randVec2F(): auto = newVec2(rand(10'f) + 0.01, rand(10'f) + 0.01) +proc randVec3I(): auto = newVec3(rand(1 .. 10), rand(1 .. 10), rand(1 .. 10)) +proc randVec3F(): auto = newVec3(rand(10'f) + 0.01, rand(10'f) + 0.01, rand(10'f) + 0.01) +proc randVec4I(): auto = newVec4(rand(1 .. 10), rand(1 .. 10), rand(1 .. 10), rand(1 .. 10)) +proc randVec4F(): auto = newVec4(rand(10'f) + 0.01, rand(10'f) + 0.01, rand(10'f) + 0.01, rand(10'f) + 0.01) + + +proc testVector() = + echoInfo(randVec2I()) + echoInfo(randVec2F()) + echoInfo(randVec3I()) + echoInfo(randVec3F()) + echoInfo(randVec4I()) + echoInfo(randVec4F()) + + # test math operations vector-vector + echoAdd(randVec2I(), randVec2I()) + echoAdd(randVec2F(), randVec2F()) + echoAdd(randVec3I(), randVec3I()) + echoAdd(randVec3F(), randVec3F()) + echoAdd(randVec4I(), randVec4I()) + echoAdd(randVec4F(), randVec4F()) + echoSub(randVec2I(), randVec2I()) + echoSub(randVec2F(), randVec2F()) + echoSub(randVec3I(), randVec3I()) + echoSub(randVec3F(), randVec3F()) + echoSub(randVec4I(), randVec4I()) + echoSub(randVec4F(), randVec4F()) + echoMul(randVec2I(), randVec2I()) + echoMul(randVec2F(), randVec2F()) + echoMul(randVec3I(), randVec3I()) + echoMul(randVec3F(), randVec3F()) + echoMul(randVec4I(), randVec4I()) + echoMul(randVec4F(), randVec4F()) + echoDiv(randVec2I(), randVec2I()) + echoDiv(randVec2F(), randVec2F()) + echoDiv(randVec3I(), randVec3I()) + echoDiv(randVec3F(), randVec3F()) + echoDiv(randVec4I(), randVec4I()) + echoDiv(randVec4F(), randVec4F()) + echoDot(randVec2I(), randVec2I()) + echoDot(randVec2F(), randVec2F()) + echoDot(randVec3I(), randVec3I()) + echoDot(randVec3F(), randVec3F()) + echoDot(randVec4I(), randVec4I()) + echoDot(randVec4F(), randVec4F()) + echoCross(randVec3I(), randVec3I()) + echoCross(randVec3F(), randVec3F()) + + + # test math operations vector-scalar + echoAdd(randVec2I(), rand(1 .. 10)) + echoAdd(randVec2F(), rand(10'f)) + echoAdd(randVec3I(), rand(1 .. 10)) + echoAdd(randVec3F(), rand(10'f)) + echoAdd(randVec4I(), rand(1 .. 10)) + echoAdd(randVec4F(), rand(10'f)) + echoSub(randVec2I(), rand(1 .. 10)) + echoSub(randVec2F(), rand(10'f)) + echoSub(randVec3I(), rand(1 .. 10)) + echoSub(randVec3F(), rand(10'f)) + echoSub(randVec4I(), rand(1 .. 10)) + echoSub(randVec4F(), rand(10'f)) + echoMul(randVec2I(), rand(1 .. 10)) + echoMul(randVec2F(), rand(10'f)) + echoMul(randVec3I(), rand(1 .. 10)) + echoMul(randVec3F(), rand(10'f)) + echoMul(randVec4I(), rand(1 .. 10)) + echoMul(randVec4F(), rand(10'f)) + echoDiv(randVec2I(), rand(1 .. 10)) + echoDiv(randVec2F(), rand(10'f)) + echoDiv(randVec3I(), rand(1 .. 10)) + echoDiv(randVec3F(), rand(10'f)) + echoDiv(randVec4I(), rand(1 .. 10)) + echoDiv(randVec4F(), rand(10'f)) + + # test math operations scalar-vector + echoAdd(rand(1 .. 10), randVec2I()) + echoAdd(rand(10'f), randVec2F()) + echoAdd(rand(1 .. 10), randVec3I()) + echoAdd(rand(10'f), randVec3F()) + echoAdd(rand(1 .. 10), randVec4I()) + echoAdd(rand(10'f), randVec4F()) + echoSub(rand(1 .. 10), randVec2I()) + echoSub(rand(10'f), randVec2F()) + echoSub(rand(1 .. 10), randVec3I()) + echoSub(rand(10'f), randVec3F()) + echoSub(rand(1 .. 10), randVec4I()) + echoSub(rand(10'f), randVec4F()) + echoMul(rand(1 .. 10), randVec2I()) + echoMul(rand(10'f), randVec2F()) + echoMul(rand(1 .. 10), randVec3I()) + echoMul(rand(10'f), randVec3F()) + echoMul(rand(1 .. 10), randVec4I()) + echoMul(rand(10'f), randVec4F()) + echoDiv(rand(1 .. 10), randVec2I()) + echoDiv(rand(10'f), randVec2F()) + echoDiv(rand(1 .. 10), randVec3I()) + echoDiv(rand(10'f), randVec3F()) + echoDiv(rand(1 .. 10), randVec4I()) + echoDiv(rand(10'f), randVec4F()) + + # test attribute syntax sugar + echo "float2int ", to[int](randVec2F()) + echo "int2float ", to[float](randVec2I()) + echo "float2int ", to[int](randVec3F()) + echo "int2float ", to[float](randVec3I()) + echo "float2int ", to[int](randVec3F()) + echo "int2float ", to[float](randVec3I()) + + echo "V2I.xx: ", randVec2I().xx + echo "V2I.yx: ", randVec2I().xy + echo "V2F.xx: ", randVec2F().xx + echo "V2F.yx: ", randVec2F().yx + echo "V2I.rr: ", randVec2I().rr + echo "V2I.gr: ", randVec2I().gr + echo "V2F.rr: ", randVec2F().rr + echo "V2F.gr: ", randVec2F().gr + + echo "V3I.yyy: ", randVec3I().yyy + echo "V3I.yxz: ", randVec3I().xyz + echo "V3F.yyy: ", randVec3F().yyy + echo "V3F.yxz: ", randVec3F().yxz + echo "V3I.ggg: ", randVec3I().ggg + echo "V3I.grb: ", randVec3I().grb + echo "V3F.ggg: ", randVec3F().ggg + echo "V3F.grb: ", randVec3F().grb + + echo "V4I.zzzz: ", randVec4I().zzzz + echo "V4I.yxzw: ", randVec4I().xyzw + echo "V4F.zzzz: ", randVec4F().zzzz + echo "V4F.yxzw: ", randVec4F().yxzw + echo "V4I.bbbb: ", randVec4I().bbbb + echo "V4I.grba: ", randVec4I().grba + echo "V4F.bbbb: ", randVec4F().bbbb + echo "V4F.grba: ", randVec4F().grba + + echo "X: ", X + echo "Y: ", Y + echo "Z: ", Z + echo "X: ", Xi + echo "Y: ", Yi + echo "Z: ", Zi + + +template withAllIntegerMats(stuff: untyped) = + stuff(Mat22[int32]) + stuff(Mat23[int32]) + stuff(Mat32[int32]) + stuff(Mat33[int32]) + stuff(Mat34[int32]) + stuff(Mat43[int32]) + stuff(Mat44[int32]) + stuff(Mat22[int64]) + stuff(Mat23[int64]) + stuff(Mat32[int64]) + stuff(Mat33[int64]) + stuff(Mat34[int64]) + stuff(Mat43[int64]) + stuff(Mat44[int64]) + +template withAllFloatMats(stuff: untyped) = + stuff(Mat22[float32]) + stuff(Mat23[float32]) + stuff(Mat32[float32]) + stuff(Mat33[float32]) + stuff(Mat34[float32]) + stuff(Mat43[float32]) + stuff(Mat44[float32]) + stuff(Mat22[float64]) + stuff(Mat23[float64]) + stuff(Mat32[float64]) + stuff(Mat33[float64]) + stuff(Mat34[float64]) + stuff(Mat43[float64]) + stuff(Mat44[float64]) + +template withAllMats(stuff: untyped) = + stuff(Mat22[int]) + stuff(Mat23[int]) + stuff(Mat32[int]) + stuff(Mat33[int]) + stuff(Mat34[int]) + stuff(Mat43[int]) + stuff(Mat44[int]) + stuff(Mat22[float]) + stuff(Mat23[float]) + stuff(Mat32[float]) + stuff(Mat33[float]) + stuff(Mat34[float]) + stuff(Mat43[float]) + stuff(Mat44[float]) + +template testTranspose(t: typedesc) = + echo "testTranspose: ", t + let m = t().randomized() + assert m == m.transposed().transposed() + +template testAssignI(t: typedesc) = + echo "testAssignI: ", t + var m = t() + for i in 0 ..< t.data.len: + m[rand(0 ..< m.rowCount), rand(0 ..< m.columnCount)] = rand(0'i32 .. 100'i32) + +template testAssignF(t: typedesc) = + echo "testAssignF: ", t + var m = t() + for i in 0 ..< t.data.len: + m[rand(0 ..< m.rowCount), rand(0 ..< m.columnCount)] = rand(100'f) + +template testRowCols(t: typedesc) = + echo "testRowCols: ", t + var m = t().randomized() + for i in 0 ..< m.rowCount: + echo m.row(i) + for i in 0 ..< m.columnCount: + echo m.col(i) + + +proc testMatrix() = + withAllMats(testTranspose) + withAllIntegerMats(testAssignI) + withAllFloatMats(testAssignF) + withAllMats(testRowCols) + +randomize() +testVector() +testMatrix() diff -r 04b8471bdab4 -r d4750f2e0760 tests/test_vector.nim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_vector.nim Wed Dec 28 11:42:21 2022 +0700 @@ -0,0 +1,255 @@ +import random +import math + +import vector +import matrix + + +proc echoInfo(v: Vec) = + echo v + echo " Length: ", v.length + echo " Normlized: ", v.normalized + echo " negated: ", -v + +proc echoAdd[T, U](v1: T, v2: U) = + echo v1, " + ", v2, " = ", v1 + v2 +proc echoSub[T, U](v1: T, v2: U) = + echo v1, " - ", v2, " = ", v1 - v2 +proc echoMul[T, U](v1: T, v2: U) = + echo v1, " * ", v2, " = ", v1 * v2 +proc echoDiv[T, U](v1: T, v2: U) = + echo v1, " / ", v2, " = ", v1 / v2 +proc echoDot[T, U](v1: T, v2: U) = + echo v1, " o ", v2, " = ", v1.dot(v2) +proc echoCross[T, U](v1: T, v2: U) = + echo v1, " x ", v2, " = ", v1.cross(v2) + +proc randVec2I(): auto = newVec2(rand(1 .. 10), rand(1 .. 10)) +proc randVec2F(): auto = newVec2(rand(10'f) + 0.01, rand(10'f) + 0.01) +proc randVec3I(): auto = newVec3(rand(1 .. 10), rand(1 .. 10), rand(1 .. 10)) +proc randVec3F(): auto = newVec3(rand(10'f) + 0.01, rand(10'f) + 0.01, rand(10'f) + 0.01) +proc randVec4I(): auto = newVec4(rand(1 .. 10), rand(1 .. 10), rand(1 .. 10), rand(1 .. 10)) +proc randVec4F(): auto = newVec4(rand(10'f) + 0.01, rand(10'f) + 0.01, rand(10'f) + 0.01, rand(10'f) + 0.01) + + +proc testVector() = + echoInfo(randVec2I()) + echoInfo(randVec2F()) + echoInfo(randVec3I()) + echoInfo(randVec3F()) + echoInfo(randVec4I()) + echoInfo(randVec4F()) + + # test math operations vector-vector + echoAdd(randVec2I(), randVec2I()) + echoAdd(randVec2F(), randVec2F()) + echoAdd(randVec3I(), randVec3I()) + echoAdd(randVec3F(), randVec3F()) + echoAdd(randVec4I(), randVec4I()) + echoAdd(randVec4F(), randVec4F()) + echoSub(randVec2I(), randVec2I()) + echoSub(randVec2F(), randVec2F()) + echoSub(randVec3I(), randVec3I()) + echoSub(randVec3F(), randVec3F()) + echoSub(randVec4I(), randVec4I()) + echoSub(randVec4F(), randVec4F()) + echoMul(randVec2I(), randVec2I()) + echoMul(randVec2F(), randVec2F()) + echoMul(randVec3I(), randVec3I()) + echoMul(randVec3F(), randVec3F()) + echoMul(randVec4I(), randVec4I()) + echoMul(randVec4F(), randVec4F()) + echoDiv(randVec2I(), randVec2I()) + echoDiv(randVec2F(), randVec2F()) + echoDiv(randVec3I(), randVec3I()) + echoDiv(randVec3F(), randVec3F()) + echoDiv(randVec4I(), randVec4I()) + echoDiv(randVec4F(), randVec4F()) + echoDot(randVec2I(), randVec2I()) + echoDot(randVec2F(), randVec2F()) + echoDot(randVec3I(), randVec3I()) + echoDot(randVec3F(), randVec3F()) + echoDot(randVec4I(), randVec4I()) + echoDot(randVec4F(), randVec4F()) + echoCross(randVec3I(), randVec3I()) + echoCross(randVec3F(), randVec3F()) + + + # test math operations vector-scalar + echoAdd(randVec2I(), rand(1 .. 10)) + echoAdd(randVec2F(), rand(10'f)) + echoAdd(randVec3I(), rand(1 .. 10)) + echoAdd(randVec3F(), rand(10'f)) + echoAdd(randVec4I(), rand(1 .. 10)) + echoAdd(randVec4F(), rand(10'f)) + echoSub(randVec2I(), rand(1 .. 10)) + echoSub(randVec2F(), rand(10'f)) + echoSub(randVec3I(), rand(1 .. 10)) + echoSub(randVec3F(), rand(10'f)) + echoSub(randVec4I(), rand(1 .. 10)) + echoSub(randVec4F(), rand(10'f)) + echoMul(randVec2I(), rand(1 .. 10)) + echoMul(randVec2F(), rand(10'f)) + echoMul(randVec3I(), rand(1 .. 10)) + echoMul(randVec3F(), rand(10'f)) + echoMul(randVec4I(), rand(1 .. 10)) + echoMul(randVec4F(), rand(10'f)) + echoDiv(randVec2I(), rand(1 .. 10)) + echoDiv(randVec2F(), rand(10'f)) + echoDiv(randVec3I(), rand(1 .. 10)) + echoDiv(randVec3F(), rand(10'f)) + echoDiv(randVec4I(), rand(1 .. 10)) + echoDiv(randVec4F(), rand(10'f)) + + # test math operations scalar-vector + echoAdd(rand(1 .. 10), randVec2I()) + echoAdd(rand(10'f), randVec2F()) + echoAdd(rand(1 .. 10), randVec3I()) + echoAdd(rand(10'f), randVec3F()) + echoAdd(rand(1 .. 10), randVec4I()) + echoAdd(rand(10'f), randVec4F()) + echoSub(rand(1 .. 10), randVec2I()) + echoSub(rand(10'f), randVec2F()) + echoSub(rand(1 .. 10), randVec3I()) + echoSub(rand(10'f), randVec3F()) + echoSub(rand(1 .. 10), randVec4I()) + echoSub(rand(10'f), randVec4F()) + echoMul(rand(1 .. 10), randVec2I()) + echoMul(rand(10'f), randVec2F()) + echoMul(rand(1 .. 10), randVec3I()) + echoMul(rand(10'f), randVec3F()) + echoMul(rand(1 .. 10), randVec4I()) + echoMul(rand(10'f), randVec4F()) + echoDiv(rand(1 .. 10), randVec2I()) + echoDiv(rand(10'f), randVec2F()) + echoDiv(rand(1 .. 10), randVec3I()) + echoDiv(rand(10'f), randVec3F()) + echoDiv(rand(1 .. 10), randVec4I()) + echoDiv(rand(10'f), randVec4F()) + + # test attribute syntax sugar + echo "float2int ", to[int](randVec2F()) + echo "int2float ", to[float](randVec2I()) + echo "float2int ", to[int](randVec3F()) + echo "int2float ", to[float](randVec3I()) + echo "float2int ", to[int](randVec3F()) + echo "int2float ", to[float](randVec3I()) + + echo "V2I.xx: ", randVec2I().xx + echo "V2I.yx: ", randVec2I().xy + echo "V2F.xx: ", randVec2F().xx + echo "V2F.yx: ", randVec2F().yx + echo "V2I.rr: ", randVec2I().rr + echo "V2I.gr: ", randVec2I().gr + echo "V2F.rr: ", randVec2F().rr + echo "V2F.gr: ", randVec2F().gr + + echo "V3I.yyy: ", randVec3I().yyy + echo "V3I.yxz: ", randVec3I().xyz + echo "V3F.yyy: ", randVec3F().yyy + echo "V3F.yxz: ", randVec3F().yxz + echo "V3I.ggg: ", randVec3I().ggg + echo "V3I.grb: ", randVec3I().grb + echo "V3F.ggg: ", randVec3F().ggg + echo "V3F.grb: ", randVec3F().grb + + echo "V4I.zzzz: ", randVec4I().zzzz + echo "V4I.yxzw: ", randVec4I().xyzw + echo "V4F.zzzz: ", randVec4F().zzzz + echo "V4F.yxzw: ", randVec4F().yxzw + echo "V4I.bbbb: ", randVec4I().bbbb + echo "V4I.grba: ", randVec4I().grba + echo "V4F.bbbb: ", randVec4F().bbbb + echo "V4F.grba: ", randVec4F().grba + + echo "X: ", X + echo "Y: ", Y + echo "Z: ", Z + echo "X: ", Xi + echo "Y: ", Yi + echo "Z: ", Zi + + +template withAllIntegerMats(stuff: untyped) = + stuff(Mat22[int32]) + stuff(Mat23[int32]) + stuff(Mat32[int32]) + stuff(Mat33[int32]) + stuff(Mat34[int32]) + stuff(Mat43[int32]) + stuff(Mat44[int32]) + stuff(Mat22[int64]) + stuff(Mat23[int64]) + stuff(Mat32[int64]) + stuff(Mat33[int64]) + stuff(Mat34[int64]) + stuff(Mat43[int64]) + stuff(Mat44[int64]) + +template withAllFloatMats(stuff: untyped) = + stuff(Mat22[float32]) + stuff(Mat23[float32]) + stuff(Mat32[float32]) + stuff(Mat33[float32]) + stuff(Mat34[float32]) + stuff(Mat43[float32]) + stuff(Mat44[float32]) + stuff(Mat22[float64]) + stuff(Mat23[float64]) + stuff(Mat32[float64]) + stuff(Mat33[float64]) + stuff(Mat34[float64]) + stuff(Mat43[float64]) + stuff(Mat44[float64]) + +template withAllMats(stuff: untyped) = + stuff(Mat22[int]) + stuff(Mat23[int]) + stuff(Mat32[int]) + stuff(Mat33[int]) + stuff(Mat34[int]) + stuff(Mat43[int]) + stuff(Mat44[int]) + stuff(Mat22[float]) + stuff(Mat23[float]) + stuff(Mat32[float]) + stuff(Mat33[float]) + stuff(Mat34[float]) + stuff(Mat43[float]) + stuff(Mat44[float]) + +template testTranspose(t: typedesc) = + echo "testTranspose: ", t + let m = t().randomized() + assert m == m.transposed().transposed() + +template testAssignI(t: typedesc) = + echo "testAssignI: ", t + var m = t() + for i in 0 ..< t.data.len: + m[rand(0 ..< m.rowCount), rand(0 ..< m.columnCount)] = rand(0'i32 .. 100'i32) + +template testAssignF(t: typedesc) = + echo "testAssignF: ", t + var m = t() + for i in 0 ..< t.data.len: + m[rand(0 ..< m.rowCount), rand(0 ..< m.columnCount)] = rand(100'f) + +template testRowCols(t: typedesc) = + echo "testRowCols: ", t + var m = t().randomized() + for i in 0 ..< m.rowCount: + echo m.row(i) + for i in 0 ..< m.columnCount: + echo m.col(i) + + +proc testMatrix() = + withAllMats(testTranspose) + withAllIntegerMats(testAssignI) + withAllFloatMats(testAssignF) + withAllMats(testRowCols) + +randomize() +testVector() +testMatrix()