From 6db149a2be0c7d49ac72668e2aead2b1ac670e9e Mon Sep 17 00:00:00 2001 From: treeform Date: Sat, 8 May 2021 11:00:29 -0700 Subject: [PATCH] Add 3 different vector/matrix representations. (#32) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add -d:vmathArrayBased to go to array vectors (slow). * Add -d:vmathObjBased to go to object vectors (faster). * Add default or just add -d:vmathObjArrayBased to go to object-array vectors (fastest). Current speed test (using pixie, your results may vary): ``` nim c -r -d:release -d:vmathArrayBased .\tests\benchmark_svg.nim svg decode ........................ 31.543 ms 38.110 ms ±5.531 x1000 nim c -r -d:release -d:vmathObjBased .\tests\benchmark_svg.nim svg decode ........................ 25.620 ms 33.569 ms ±6.328 x1000 nim c -r -d:release .\tests\benchmark_svg.nim svg decode ........................ 25.746 ms 33.059 ms ±5.666 x1000 ``` --- src/vmath.nim | 801 +++++++++++++++++++++++++++++++------------- tests/bench_rep.nim | 262 +++++++++++++++ tests/test.nim | 211 +++++++----- 3 files changed, 963 insertions(+), 311 deletions(-) create mode 100644 tests/bench_rep.nim diff --git a/src/vmath.nim b/src/vmath.nim index c03fec3..f38db9f 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -1,12 +1,347 @@ +## +## -d:vmathObjBased +## -d:vmathArrayBased +## default: ObjArray based +## + import math export math -type - GVec2*[T] = array[2, T] - GVec3*[T] = array[3, T] - GVec4*[T] = array[4, T] +{.push inline.} +when defined(release): + {.push noinit, checks: off.} +when defined(vmathArrayBased): + type + GVec2*[T] = array[2, T] + GVec3*[T] = array[3, T] + GVec4*[T] = array[4, T] + GVec34[T] = GVec3[T] | GVec4[T] + GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T] + + template gvec2*[T](x, y: T): GVec2[T] = [T(x), T(y)] + template gvec3*[T](x, y, z: T): GVec3[T] = [T(x), T(y), T(z)] + template gvec4*[T](x, y, z, w: T): GVec4[T] = [T(x), T(y), T(z), T(w)] + + template x*[T](a: GVec2[T]): T = a[0] + template x*[T](a: GVec3[T]): T = a[0] + template x*[T](a: GVec4[T]): T = a[0] + + template y*[T](a: GVec2[T]): T = a[1] + template y*[T](a: GVec3[T]): T = a[1] + template y*[T](a: GVec4[T]): T = a[1] + + template z*[T](a: GVec2[T]): T = {.error: "using .w on a Vec2".} + template z*[T](a: GVec3[T]): T = a[2] + template z*[T](a: GVec4[T]): T = a[2] + + template w*[T](a: GVec2[T]): T = {.error: "using .w on a Vec2".} + template w*[T](a: GVec3[T]): T = {.error: "using .w on a Vec3".} + template w*[T](a: GVec4[T]): T = a[3] + + template x*[T](a: var GVec2[T]): var T = a[0] + template x*[T](a: var GVec3[T]): var T = a[0] + template x*[T](a: var GVec4[T]): var T = a[0] + template y*[T](a: var GVec2[T]): var T = a[1] + template y*[T](a: var GVec3[T]): var T = a[1] + template y*[T](a: var GVec4[T]): var T = a[1] + template z*[T](a: var GVec3[T]): var T = a[2] + template z*[T](a: var GVec4[T]): var T = a[2] + template w*[T](a: var GVec4[T]): var T = a[3] + + template `x=`*[T](a: var GVec234[T], value: T) = a[0] = value + template `y=`*[T](a: var GVec234[T], value: T) = a[1] = value + template `z=`*[T](a: var GVec34[T], value: T) = a[2] = value + template `w=`*[T](a: var GVec4[T], value: T) = a[3] = value + + type + GMat2*[T] = array[2, GVec2[T]] + GMat3*[T] = array[3, GVec3[T]] + GMat4*[T] = array[4, GVec4[T]] + + GMat234[T] = GMat2[T] | GMat3[T] | GMat4[T] + + proc gmat2*[T]( + m00, m01, + m10, m11: T + ): GMat2[T] = + [ + [m00, m01], + [m10, m11] + ] + + proc gmat3*[T]( + m00, m01, m02, + m10, m11, m12, + m20, m21, m22: T + ): GMat3[T] = + [ + [m00, m01, m02], + [m10, m11, m12], + [m20, m21, m22] + ] + + proc gmat4*[T]( + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33: T + ): GMat4[T] = + [ + [m00, m01, m02, m03], + [m10, m11, m12, m13], + [m20, m21, m22, m23], + [m30, m31, m32, m33] + ] + + template `[]`*[T](a: GMat234[T], i, j: int): T = a[i][j] + + template `[]=`*[T](a: var GMat2[T], i, j: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + (i * 2 + j) * sizeof(T))[] = v + + template `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + (i * 3 + j) * sizeof(T))[] = v + + template `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + (i * 4 + j) * sizeof(T))[] = v + +elif defined(vmathObjBased): + type + GVec2*[T] = object + x*, y*: T + GVec3*[T] = object + x*, y*, z*: T + GVec4*[T] = object + x*, y*, z*, w*: T + GVec34[T] = GVec3[T] | GVec4[T] + GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T] + + template gvec2*[T](mx, my: T): GVec2[T] = + GVec2[T](x: mx, y: my) + + template gvec3*[T](mx, my, mz: T): GVec3[T] = + GVec3[T](x: mx, y: my, z: mz) + + template gvec4*[T](mx, my, mz, mw: T): GVec4[T] = + GVec4[T](x: mx, y: my, z: mz, w: mw) + + template `[]`*[T](a: GVec2[T], i: int): T = cast[array[2, T]](a)[i] + template `[]`*[T](a: GVec3[T], i: int): T = cast[array[3, T]](a)[i] + template `[]`*[T](a: GVec4[T], i: int): T = cast[array[4, T]](a)[i] + + template `[]=`*[T](a: var GVec2[T], i: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + i * sizeof(T))[] = v + + template `[]=`*[T](a: var GVec3[T], i: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + i * sizeof(T))[] = v + + template `[]=`*[T](a: var GVec4[T], i: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + i * sizeof(T))[] = v + + type + GMat2*[T] = object + m00*, m01*: T + m10*, m11*: T + GMat3*[T] = object + m00*, m01*, m02*: T + m10*, m11*, m12*: T + m20*, m21*, m22*: T + GMat4*[T] = object + m00*, m01*, m02*, m03*: T + m10*, m11*, m12*, m13*: T + m20*, m21*, m22*, m23*: T + m30*, m31*, m32*, m33*: T + + proc gmat2*[T]( + m00, m01, + m10, m11: T + ): GMat2[T] = + result.m00 = m00; result.m01 = m01 + result.m10 = m10; result.m11 = m11 + + proc gmat3*[T]( + m00, m01, m02, + m10, m11, m12, + m20, m21, m22: T + ): GMat3[T] = + result.m00 = m00; result.m01 = m01; result.m02 = m02 + result.m10 = m10; result.m11 = m11; result.m12 = m12 + result.m20 = m20; result.m21 = m21; result.m22 = m22 + + proc gmat4*[T]( + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33: T + ): GMat4[T] = + result.m00 = m00; result.m01 = m01; result.m02 = m02; result.m03 = m03 + result.m10 = m10; result.m11 = m11; result.m12 = m12; result.m13 = m13 + result.m20 = m20; result.m21 = m21; result.m22 = m22; result.m23 = m23 + result.m30 = m30; result.m31 = m31; result.m32 = m32; result.m33 = m33 + + template `[]`*[T](a: GMat2[T], i, j: int): T = + cast[array[4, T]](a)[i * 2 + j] + + template `[]`*[T](a: GMat3[T], i, j: int): T = + cast[array[9, T]](a)[i * 3 + j] + + template `[]`*[T](a: GMat4[T], i, j: int): T = + cast[array[16, T]](a)[i * 4 + j] + + template `[]=`*[T](a: var GMat2[T], i, j: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + (i * 2 + j) * sizeof(T))[] = v + + template `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + (i * 3 + j) * sizeof(T))[] = v + + template `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = + cast[ptr T](cast[uint64](a.addr) + (i * 4 + j) * sizeof(T))[] = v + + template `[]`*[T](a: GMat2[T], i: int): GVec2[T] = + gvec2[T]( + a[i, 0], + a[i, 1] + ) + + template `[]`*[T](a: GMat3[T], i: int): GVec3[T] = + gvec3[T]( + a[i, 0], + a[i, 1], + a[i, 2] + ) + + template `[]`*[T](a: GMat4[T], i: int): GVec4[T] = + gvec4[T]( + a[i, 0], + a[i, 1], + a[i, 2], + a[i, 3] + ) + +elif true or defined(vmathObjArrayBased): + type + GVec2*[T] = object + arr: array[2, T] + GVec3*[T] = object + arr: array[3, T] + GVec4*[T] = object + arr: array[4, T] + GVec34[T] = GVec3[T] | GVec4[T] + GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T] + + template gvec2*[T](x, y: T): GVec2[T] = + GVec2[T](arr:[T(x), T(y)]) + + template gvec3*[T](x, y, z: T): GVec3[T] = + GVec3[T](arr:[T(x), T(y), T(z)]) + + template gvec4*[T](x, y, z, w: T): GVec4[T] = + GVec4[T](arr:[T(x), T(y), T(z), T(w)]) + + template x*[T](a: var GVec2[T]): var T = a.arr[0] + template y*[T](a: var GVec2[T]): var T = a.arr[1] + + template x*[T](a: var GVec3[T]): var T = a.arr[0] + template y*[T](a: var GVec3[T]): var T = a.arr[1] + template z*[T](a: var GVec3[T]): var T = a.arr[2] + + template x*[T](a: var GVec4[T]): var T = a.arr[0] + template y*[T](a: var GVec4[T]): var T = a.arr[1] + template z*[T](a: var GVec4[T]): var T = a.arr[2] + template w*[T](a: var GVec4[T]): var T = a.arr[3] + + template x*[T](a: GVec2[T]): T = a.arr[0] + template x*[T](a: GVec3[T]): T = a.arr[0] + template x*[T](a: GVec4[T]): T = a.arr[0] + + template y*[T](a: GVec2[T]): T = a.arr[1] + template y*[T](a: GVec3[T]): T = a.arr[1] + template y*[T](a: GVec4[T]): T = a.arr[1] + + template z*[T](a: GVec3[T]): T = a.arr[2] + template z*[T](a: GVec4[T]): T = a.arr[2] + template w*[T](a: GVec4[T]): T = a.arr[3] + + template `x=`*[T](a: var GVec234[T], value: T) = a.arr[0] = value + template `y=`*[T](a: var GVec234[T], value: T) = a.arr[1] = value + template `z=`*[T](a: var GVec34[T], value: T) = a.arr[2] = value + template `w=`*[T](a: var GVec4[T], value: T) = a.arr[3] = value + + template `[]`*[T](a: GVec234[T], i: int): T = a.arr[i] + template `[]=`*[T](a: var GVec234[T], i: int, v: T) = a.arr[i] = v + + type + GMat2*[T] = object + arr: array[4, T] + GMat3*[T] = object + arr: array[9, T] + GMat4*[T] = object + arr: array[16, T] + + proc gmat2*[T]( + m00, m01, + m10, m11: T + ): GMat2[T] = + GMat2[T](arr: [ + m00, m01, + m10, m11 + ]) + + proc gmat3*[T]( + m00, m01, m02, + m10, m11, m12, + m20, m21, m22: T + ): GMat3[T] = + GMat3[T](arr: [ + m00, m01, m02, + m10, m11, m12, + m20, m21, m22 + ]) + + proc gmat4*[T]( + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33: T + ): GMat4[T] = + GMat4[T](arr: [ + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33 + ]) + + template `[]`*[T](a: GMat2[T], i, j: int): T = a.arr[i * 2 + j] + template `[]`*[T](a: GMat3[T], i, j: int): T = a.arr[i * 3 + j] + template `[]`*[T](a: GMat4[T], i, j: int): T = a.arr[i * 4 + j] + + template `[]=`*[T](a: var GMat2[T], i, j: int, v: T) = a.arr[i * 2 + j] = v + template `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = a.arr[i * 3 + j] = v + template `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = a.arr[i * 4 + j] = v + + template `[]`*[T](a: GMat2[T], i: int): GVec2[T] = + gvec2[T]( + a[i, 0], + a[i, 1] + ) + + template `[]`*[T](a: GMat3[T], i: int): GVec3[T] = + gvec3[T]( + a[i, 0], + a[i, 1], + a[i, 2] + ) + + template `[]`*[T](a: GMat4[T], i: int): GVec4[T] = + gvec4[T]( + a[i, 0], + a[i, 1], + a[i, 2], + a[i, 3] + ) + +type BVec2* = GVec2[bool] BVec3* = GVec3[bool] BVec4* = GVec4[bool] @@ -27,13 +362,6 @@ type DVec3* = GVec3[float64] DVec4* = GVec4[float64] - GVec34[T] = GVec3[T] | GVec4[T] - GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T] - -{.push inline.} -when defined(release): - {.push noinit, checks: off.} - proc `~=`*[T: SomeFloat](a, b: T): bool = ## Almost equal. const epsilon = 0.000001 @@ -91,21 +419,19 @@ proc turnAngle*[T: SomeFloat](a, b, speed: T): T = a + turn proc toRadians*[T: SomeFloat](deg: T): T = + ## Convert degrees to radians. return PI * deg / 180.0 proc toDegrees*[T: SomeFloat](rad: T): T = + ## Convert radians to degrees. return fixAngle(180.0 * rad / PI) -proc gvec2*[T](x, y: T): GVec2[T] = - [x, y] - -proc gvec3*[T](x, y, z: T): GVec3[T] = - [x, y, z] - -proc gvec4*[T](x, y, z, w: T): GVec4[T] = - [x, y, z, w] - template genConstructor(lower, upper, typ: untyped) = + + proc `lower 2`*(): `upper 2` = gvec2[typ](typ(0), typ(0)) + proc `lower 3`*(): `upper 3` = gvec3[typ](typ(0), typ(0), typ(0)) + proc `lower 4`*(): `upper 4` = gvec4[typ](typ(0), typ(0), typ(0), typ(0)) + proc `lower 2`*(x, y: typ): `upper 2` = gvec2[typ](x, y) proc `lower 3`*(x, y, z: typ): `upper 3` = gvec3[typ](x, y, z) proc `lower 4`*(x, y, z, w: typ): `upper 4` = gvec4[typ](x, y, z, w) @@ -132,137 +458,104 @@ genConstructor(uvec, UVec, uint32) genConstructor(vec, Vec, float32) genConstructor(dvec, DVec, float64) -proc x*[T](a: var GVec2[T]): var T = a[0] -proc y*[T](a: var GVec2[T]): var T = a[1] +proc xy*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.x, a.y) +proc xz*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.x, a.z) +proc yx*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.y, a.x) +proc yz*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.y, a.z) +proc zx*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.z, a.x) +proc zy*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.z, a.y) -proc x*[T](a: var GVec3[T]): var T = a[0] -proc y*[T](a: var GVec3[T]): var T = a[1] -proc z*[T](a: var GVec3[T]): var T = a[2] - -proc x*[T](a: var GVec4[T]): var T = a[0] -proc y*[T](a: var GVec4[T]): var T = a[1] -proc z*[T](a: var GVec4[T]): var T = a[2] -proc w*[T](a: var GVec4[T]): var T = a[3] - -proc x*[T](a: GVec2[T]): T = a[0] -proc x*[T](a: GVec3[T]): T = a[0] -proc x*[T](a: GVec4[T]): T = a[0] - -proc y*[T](a: GVec2[T]): T = a[1] -proc y*[T](a: GVec3[T]): T = a[1] -proc y*[T](a: GVec4[T]): T = a[1] - -proc z*[T](a: GVec2[T]): T = {.error: "using .w on a Vec2".} -proc z*[T](a: GVec3[T]): T = a[2] -proc z*[T](a: GVec4[T]): T = a[2] - -proc w*[T](a: GVec2[T]): T = {.error: "using .w on a Vec2".} -proc w*[T](a: GVec3[T]): T = {.error: "using .w on a Vec3".} -proc w*[T](a: GVec4[T]): T = a[3] - -proc `x=`*[T](a: var GVec234[T], value: T) = a[0] = value -proc `y=`*[T](a: var GVec234[T], value: T) = a[1] = value -proc `z=`*[T](a: var GVec34[T], value: T) = a[2] = value -proc `w=`*[T](a: var GVec4[T], value: T) = a[3] = value - -proc xy*[T](a: GVec234[T]): GVec2[T] = [a.x, a.y] -proc xz*[T](a: GVec234[T]): GVec2[T] = [a.x, a.z] -proc yx*[T](a: GVec234[T]): GVec2[T] = [a.y, a.x] -proc yz*[T](a: GVec234[T]): GVec2[T] = [a.y, a.z] -proc zx*[T](a: GVec234[T]): GVec2[T] = [a.z, a.x] -proc zy*[T](a: GVec234[T]): GVec2[T] = [a.z, a.y] - -proc xxx*[T](a: GVec34[T]): GVec3[T] = [a.x, a.x, a.x] -proc xxy*[T](a: GVec34[T]): GVec3[T] = [a.x, a.x, a.y] -proc xxz*[T](a: GVec34[T]): GVec3[T] = [a.x, a.x, a.z] -proc xyx*[T](a: GVec34[T]): GVec3[T] = [a.x, a.y, a.x] -proc xyy*[T](a: GVec34[T]): GVec3[T] = [a.x, a.y, a.y] -proc xyz*[T](a: GVec34[T]): GVec3[T] = [a.x, a.y, a.z] -proc xzx*[T](a: GVec34[T]): GVec3[T] = [a.x, a.z, a.x] -proc xzy*[T](a: GVec34[T]): GVec3[T] = [a.x, a.z, a.y] -proc xzz*[T](a: GVec34[T]): GVec3[T] = [a.x, a.z, a.z] -proc yxx*[T](a: GVec34[T]): GVec3[T] = [a.y, a.x, a.x] -proc yxy*[T](a: GVec34[T]): GVec3[T] = [a.y, a.x, a.y] -proc yxz*[T](a: GVec34[T]): GVec3[T] = [a.y, a.x, a.z] -proc yyx*[T](a: GVec34[T]): GVec3[T] = [a.y, a.y, a.x] -proc yyy*[T](a: GVec34[T]): GVec3[T] = [a.y, a.y, a.y] -proc yyz*[T](a: GVec34[T]): GVec3[T] = [a.y, a.y, a.z] -proc yzx*[T](a: GVec34[T]): GVec3[T] = [a.y, a.z, a.x] -proc yzy*[T](a: GVec34[T]): GVec3[T] = [a.y, a.z, a.y] -proc yzz*[T](a: GVec34[T]): GVec3[T] = [a.y, a.z, a.z] -proc zxx*[T](a: GVec34[T]): GVec3[T] = [a.z, a.x, a.x] -proc zxy*[T](a: GVec34[T]): GVec3[T] = [a.z, a.x, a.y] -proc zxz*[T](a: GVec34[T]): GVec3[T] = [a.z, a.x, a.z] -proc zyx*[T](a: GVec34[T]): GVec3[T] = [a.z, a.y, a.x] -proc zyy*[T](a: GVec34[T]): GVec3[T] = [a.z, a.y, a.y] -proc zyz*[T](a: GVec34[T]): GVec3[T] = [a.z, a.y, a.z] -proc zzx*[T](a: GVec34[T]): GVec3[T] = [a.z, a.z, a.x] -proc zzy*[T](a: GVec34[T]): GVec3[T] = [a.z, a.z, a.y] -proc zzz*[T](a: GVec34[T]): GVec3[T] = [a.z, a.z, a.z] +proc xxx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.x, a.x) +proc xxy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.x, a.y) +proc xxz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.x, a.z) +proc xyx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.y, a.x) +proc xyy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.y, a.y) +proc xyz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.y, a.z) +proc xzx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.z, a.x) +proc xzy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.z, a.y) +proc xzz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.z, a.z) +proc yxx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.x, a.x) +proc yxy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.x, a.y) +proc yxz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.x, a.z) +proc yyx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.y, a.x) +proc yyy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.y, a.y) +proc yyz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.y, a.z) +proc yzx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.z, a.x) +proc yzy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.z, a.y) +proc yzz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.z, a.z) +proc zxx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.x, a.x) +proc zxy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.x, a.y) +proc zxz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.x, a.z) +proc zyx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.y, a.x) +proc zyy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.y, a.y) +proc zyz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.y, a.z) +proc zzx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.z, a.x) +proc zzy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.z, a.y) +proc zzz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.z, a.z) template genOp(op: untyped) = proc op*[T](a, b: GVec2[T]): GVec2[T] = - [ + gvec2[T]( op(a[0], b[0]), op(a[1], b[1]) - ] + ) proc op*[T](a, b: GVec3[T]): GVec3[T] = - [ + gvec3[T]( op(a[0], b[0]), op(a[1], b[1]), op(a[2], b[2]) - ] + ) proc op*[T](a, b: GVec4[T]): GVec4[T] = - [ + gvec4[T]( op(a[0], b[0]), op(a[1], b[1]), op(a[2], b[2]), op(a[3], b[3]) - ] + ) proc op*[T](a: GVec2[T], b: T): GVec2[T] = - [ + gvec2[T]( op(a[0], b), op(a[1], b) - ] + ) proc op*[T](a: GVec3[T], b: T): GVec3[T] = - [ + gvec3[T]( op(a[0], b), op(a[1], b), op(a[2], b) - ] + ) proc op*[T](a: GVec4[T], b: T): GVec4[T] = - [ + gvec4[T]( op(a[0], b), op(a[1], b), op(a[2], b), op(a[3], b) - ] + ) proc op*[T](a: T, b: GVec2[T]): GVec2[T] = - [ + gvec2[T]( op(a, b[0]), op(a, b[1]) - ] + ) proc op*[T](a: T, b: GVec3[T]): GVec3[T] = - [ + gvec3[T]( op(a, b[0]), op(a, b[1]), op(a, b[2]) - ] + ) proc op*[T](a: T, b: GVec4[T]): GVec4[T] = - [ + gvec4[T]( op(a, b[0]), op(a, b[1]), op(a, b[2]), op(a, b[3]) - ] + ) genOp(`+`) genOp(`-`) @@ -273,34 +566,34 @@ genOp(`div`) template genEqOp(op: untyped) = proc op*[T](a: var GVec2[T], b: GVec2[T]) = - op(a[0], b[0]) - op(a[1], b[1]) + op(a.x, b.x) + op(a.y, b.y) proc op*[T](a: var GVec3[T], b: GVec3[T]) = - op(a[0], b[0]) - op(a[1], b[1]) - op(a[2], b[2]) + op(a.x, b.x) + op(a.y, b.y) + op(a.z, b.z) proc op*[T](a: var GVec4[T], b: GVec4[T]) = - op(a[0], b[0]) - op(a[1], b[1]) - op(a[2], b[2]) - op(a[3], b[3]) + op(a.x, b.x) + op(a.y, b.y) + op(a.z, b.z) + op(a.w, b.w) proc op*[T](a: var GVec2[T], b: T) = - op(a[0], b) - op(a[1], b) + op(a.x, b) + op(a.y, b) proc op*[T](a: var GVec3[T], b: T) = - op(a[0], b) - op(a[1], b) - op(a[2], b) + op(a.x, b) + op(a.y, b) + op(a.z, b) proc op*[T](a: var GVec4[T], b: T) = - op(a[0], b) - op(a[1], b) - op(a[2], b) - op(a[3], b) + op(a.x, b) + op(a.y, b) + op(a.z, b) + op(a.w, b) genEqOp(`+=`) genEqOp(`-=`) @@ -309,25 +602,25 @@ genEqOp(`/=`) template genMathFn(fn: untyped) = proc fn*[T](v: GVec2[T]): GVec2[T] = - [ + gvec2[T]( fn(v[0]), fn(v[1]) - ] + ) proc fn*[T](v: GVec3[T]): GVec3[T] = - [ + gvec3[T]( fn(v[0]), fn(v[1]), fn(v[2]) - ] + ) proc fn*[T](v: GVec4[T]): GVec4[T] = - [ + gvec4[T]( fn(v[0]), fn(v[1]), fn(v[2]), fn(v[3]) - ] + ) genMathFn(`-`) genMathFn(sin) @@ -395,11 +688,11 @@ proc dot*[T](a, b: GVec4[T]): T = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w proc cross*[T](a, b: GVec3[T]): GVec3[T] = - [ + gvec3( a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x - ] + ) proc dist*[T](at, to: GVec234[T]): T = (at - to).length @@ -417,10 +710,6 @@ proc dir*[T](angle: T): GVec2[T] = ] type - GMat2*[T] = array[2, GVec2[T]] - GMat3*[T] = array[3, GVec3[T]] - GMat4*[T] = array[4, GVec4[T]] - Mat2* = GMat2[float32] Mat3* = GMat3[float32] Mat4* = GMat4[float32] @@ -429,66 +718,83 @@ type DMat3* = GMat3[float64] DMat4* = GMat4[float64] - GMat234[T] = GMat2[T] | GMat3[T] | GMat4[T] - GMat34[T] = GMat3[T] | GMat4[T] - template genMatConstructor(lower, upper, T: untyped) = - proc `lower 2`*(a, b, c, d: T): `upper 2` = - [[a, b], [c, d]] - proc `lower 3`*(a, b, c, d, e, f, g, h, i: T): `upper 3` = - [[T(a), b, c], [d, e, f], [g, h, i]] + + proc `lower 2`*( + m00, m01, + m10, m11: T + ): `upper 2` = + result[0, 0] = m00; result[0, 1] = m01 + result[1, 0] = m10; result[1, 1] = m11 + + proc `lower 3`*( + m00, m01, m02, + m10, m11, m12, + m20, m21, m22: T + ): `upper 3` = + result[0, 0] = m00; result[0, 1] = m01; result[0, 2] = m02 + result[1, 0] = m10; result[1, 1] = m11; result[1, 2] = m12 + result[2, 0] = m20; result[2, 1] = m21; result[2, 2] = m22 + proc `lower 4`*( - a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p: T + m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33: T ): `upper 4` = - [[T(a), b, c, d], [e, f, g, h], [i, j, k, l], [m, n, o, p]] + result[0, 0] = m00; result[0, 1] = m01 + result[0, 2] = m02; result[0, 3] = m03 - proc `lower 2`*(a, b: GVec2[T]): `upper 2` = [a, b] - proc `lower 3`*(a, b, c: GVec3[T]): `upper 3` = [a, b, c] - proc `lower 4`*(a, b, c, d: GVec4[T]): `upper 4` = [a, b, c, d] + result[1, 0] = m10; result[1, 1] = m11 + result[1, 2] = m12; result[1, 3] = m13 - proc `lower 2`*(m: GMat3[T]): `upper 2` = [m[0].xy, m[1].xy] - proc `lower 3`*(m: GMat4[T]): `upper 3` = [m[0].xyz, m[1].xyz, [T(0), 0, 1]] + result[2, 0] = m20; result[2, 1] = m21 + result[2, 2] = m22; result[2, 3] = m23 - proc `lower 3`*(m: GMat2[T]): `upper 3` = - [ - [m[0][0], m[0][1], 0], - [m[1][0], m[1][1], 0], - [T(0), 0, 1] - ] + result[3, 0] = m30; result[3, 1] = m31 + result[3, 2] = m32; result[3, 3] = m33 - proc `lower 4`*(m: GMat3[T]): `upper 4` = - [ - [m[0][0], m[0][1], m[0][2], 0], - [m[1][0], m[1][1], m[1][2], 0], - [T(0), 0, 1, 0], - [m[2][0], m[2][1], m[2][2], 1] - ] + proc `lower 2`*(a, b: GVec2[T]): `upper 2` = + gmat2[T]( + a.x, a.y, + b.x, b.y + ) + proc `lower 3`*(a, b, c: GVec3[T]): `upper 3` = + gmat3[T]( + a.x, a.y, a.z, + b.x, b.y, b.z, + c.x, c.y, c.z, + ) + proc `lower 4`*(a, b, c, d: GVec4[T]): `upper 4` = + gmat4[T]( + a.x, a.y, a.z, a.w, + b.x, b.y, b.z, b.w, + c.x, c.y, c.z, c.w, + d.x, d.y, d.z, d.w, + ) proc `lower 2`*(): `upper 2` = - [ - [T(1), 0], - [T(0), 1] - ] + gmat2[T]( + 1.T, 0.T, + 0.T, 1.T + ) proc `lower 3`*(): `upper 3` = - [ - [T(1), 0, 0], - [T(0), 1, 0], - [T(0), 0, 1] - ] + gmat3[T]( + 1.T, 0.T, 0.T, + 0.T, 1.T, 0.T, + 0.T, 0.T, 1.T + ) proc `lower 4`*(): `upper 4` = - [ - [T(1), 0, 0, 0], - [T(0), 1, 0, 0], - [T(0), 0, 1, 0], - [T(0), 0, 0, 1] - ] + gmat4[T]( + 1.T, 0.T, 0.T, 0.T, + 0.T, 1.T, 0.T, 0.T, + 0.T, 0.T, 1.T, 0.T, + 0.T, 0.T, 0.T, 1.T + ) genMatConstructor(mat, Mat, float32) genMatConstructor(dmat, DMat, float64) -proc `[]`*[T](a: GMat234[T], i, j: int): T = a[i][j] -proc `[]=`*[T](a: var GMat234[T], i, j: int, v: T) = a[i][j] = v - proc `~=`*[T](a, b: GMat2[T]): bool = a[0] ~= b[0] and a[1] ~= b[1] @@ -499,11 +805,11 @@ proc `~=`*[T](a, b: GMat4[T]): bool = a[0] ~= b[0] and a[1] ~= b[1] and a[2] ~= b[2] and a[3] ~= b[3] proc pos*[T](a: GMat3[T]): GVec2[T] = - [a[2][0], a[2][1]] + gvec2[T](a[2].x, a[2].y) proc `pos=`*[T](a: var GMat3[T], pos: GVec2[T]) = - a[2][0] = pos.x - a[2][1] = pos.y + a[2, 0] = pos.x + a[2, 1] = pos.y proc `*`*[T](a, b: GMat3[T]): GMat3[T] = result[0, 0] = b[0, 0] * a[0, 0] + b[0, 1] * a[1, 0] + b[0, 2] * a[2, 0] @@ -519,10 +825,10 @@ proc `*`*[T](a, b: GMat3[T]): GMat3[T] = result[2, 2] = b[2, 0] * a[0, 2] + b[2, 1] * a[1, 2] + b[2, 2] * a[2, 2] proc `*`*[T](a: GMat3[T], b: GVec2[T]): GVec2[T] = - [ + gvec2[T]( a[0, 0] * b.x + a[1, 0] * b.y + a[2, 0], a[0, 1] * b.x + a[1, 1] * b.y + a[2, 1] - ] + ) proc `*`*[T](a, b: GMat4[T]): GMat4[T] = let @@ -582,28 +888,31 @@ proc `*`*[T](a, b: GMat4[T]): GMat4[T] = result[3, 3] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33 proc `*`*[T](a: GMat4[T], b: GVec3[T]): GVec3[T] = - [ + gvec3[T]( a[0, 0] * b.x + a[1, 0] * b.y + a[2, 0] * b.z + a[3, 0], a[0, 1] * b.x + a[1, 1] * b.y + a[2, 1] * b.z + a[3, 1], a[0, 2] * b.x + a[1, 2] * b.y + a[2, 2] * b.z + a[3, 2] - ] + ) proc transpose*[T](a: GMat3[T]): GMat3[T] = - [ - [a[0, 0], a[1, 0], a[2, 0]], - [a[0, 1], a[1, 1], a[2, 1]], - [a[0, 2], a[1, 2], a[2, 2]] - ] + ## Return an transpose of the matrix. + gmat3[T]( + a[0, 0], a[1, 0], a[2, 0], + a[0, 1], a[1, 1], a[2, 1], + a[0, 2], a[1, 2], a[2, 2] + ) proc transpose*[T](a: GMat4[T]): GMat4[T] = - [ - [a[0, 0], a[1, 0], a[2, 0], a[3, 0]], - [a[0, 1], a[1, 1], a[2, 1], a[3, 1]], - [a[0, 2], a[1, 2], a[2, 2], a[3, 2]], - [a[0, 3], a[1, 3], a[2, 3], a[3, 3]] - ] + ## Return an transpose of the matrix. + gmat4[T]( + a[0, 0], a[1, 0], a[2, 0], a[3, 0], + a[0, 1], a[1, 1], a[2, 1], a[3, 1], + a[0, 2], a[1, 2], a[2, 2], a[3, 2], + a[0, 3], a[1, 3], a[2, 3], a[3, 3] + ) proc determinant*[T](a: GMat4[T]): T = + ## Compute a determinant of the matrix. let a00 = a[0, 0] a01 = a[0, 1] @@ -631,6 +940,7 @@ proc determinant*[T](a: GMat4[T]): T = ) proc inverse*[T](a: GMat3[T]): GMat3[T] = + ## Return an inverse of the matrix. let determinant = ( a[0, 0] * (a[1, 1] * a[2, 2] - a[2, 1] * a[1, 2]) - @@ -652,6 +962,7 @@ proc inverse*[T](a: GMat3[T]): GMat3[T] = result[2, 2] = +(a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]) * invDet proc inverse*[T](a: GMat4[T]): GMat4[T] = + ## Return an inverse of the matrix. let a00 = a[0, 0] a01 = a[0, 1] @@ -708,46 +1019,52 @@ proc inverse*[T](a: GMat4[T]): GMat4[T] = result[3, 3] = (+a20 * b03 - a21 * b01 + a22 * b00) * invDet proc scale*[T](v: GVec2[T]): GMat3[T] = - [ - [v.x, 0, 0], - [T(0), v.y, 0], - [T(0), 0, 1] - ] + ## Create scale matrix. + gmat3[T]( + v.x, 0, 0, + 0, v.y, 0, + 0, 0, 1 + ) proc scale*[T](v: GVec3[T]): GMat4[T] = - [ - [v.x, 0, 0, 0], - [T(0), v.y, 0, 0], - [T(0), 0, v.z, 0], - [T(0), 0, 0, 1] - ] + ## Create scale matrix. + gmat4[T]( + v.x, 0, 0, 0, + 0, v.y, 0, 0, + 0, 0, v.z, 0, + 0, 0, 0, 1 + ) proc translate*[T](v: GVec2[T]): GMat3[T] = - [ - [T(1), 0, 0], - [T(0), 1, 0], - [v.x, v.y, 1] - ] + ## Create translation matrix. + gmat3[T]( + 1, 0, 0, + 0, 1, 0, + v.x, v.y, 1 + ) proc translate*[T](v: GVec3[T]): GMat4[T] = - [ - [T(1), 0, 0, 0], - [T(0), 1, 0, 0], - [T(0), 0, 1, 0], - [v.x, v.y, v.z, 1] - ] + ## Create translation matrix. + gmat4[T]( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + v.x, v.y, v.z, 1 + ) proc rotate*[T](angle: T): GMat3[T] = + ## Create a rotation matrix by an angle. let sin = sin(angle) cos = cos(angle) - [ - [cos, -sin, 0], - [sin, cos, 0], - [T(0), 0, 1] - ] + gmat3[T]( + cos, -sin, 0, + sin, cos, 0, + 0, 0, 1 + ) proc hrp*[T](m: GMat4[T]): GVec3[T] = + ## Return heading, rotation and pivot of a matrix. var heading, pitch, roll: float32 if m[1] > 0.998: # singularity at north pole heading = arctan2(m[2], m[10]) @@ -761,9 +1078,10 @@ proc hrp*[T](m: GMat4[T]): GVec3[T] = heading = arctan2(-m[8], m[0]) pitch = arctan2(-m[6], m[5]) roll = arcsin(m[4]) - [heading, pitch, roll] + gvec3[T](heading, pitch, roll) proc frustum*[T](left, right, bottom, top, near, far: T): GMat4[T] = + ## Create a frustum matrix. let rl = (right - left) tb = (top - bottom) @@ -790,12 +1108,14 @@ proc frustum*[T](left, right, bottom, top, near, far: T): GMat4[T] = result[3, 3] = 0 proc perspective*[T](fovy, aspect, near, far: T): GMat4[T] = + ## Create a perspective matrix. let top: T = near * tan(fovy * PI.float32 / 360.0) right: T = top * aspect frustum(-right, right, -top, top, near, far) proc ortho*[T](left, right, bottom, top, near, far: T): GMat4[T] = + ## Create an orthographic matrix. let rl = (right - left) tb = (top - bottom) @@ -822,6 +1142,7 @@ proc ortho*[T](left, right, bottom, top, near, far: T): GMat4[T] = result[3, 3] = 1 proc lookAt*[T](eye, center, up: GVec3[T]): GMat4[T] = + ## Create a matrix that would convert eye pos to looking at center. let eyex = eye[0] eyey = eye[1] @@ -902,7 +1223,8 @@ proc lookAt*[T](eye, center, up: GVec3[T]): GMat4[T] = result[3, 3] = 1 proc lookAt*[T](eye, center: GVec3[T]): GMat4[T] = - lookAt(eye, center, [T(0), 0, 1]) + ## Look center from eye with default UP vector. + lookAt(eye, center, gvec3(T(0), 0, 1)) proc angle*[T](a: GVec2[T]): T = ## Angle of a Vec2. @@ -923,7 +1245,6 @@ type DQuat* = GVec4[float64] template genQuatConstructor(lower, upper, typ: untyped) = - proc `lower`*(): `upper` = gvec4[typ](0, 0, 0, 1) proc `lower`*(x, y, z, w: typ): `upper` = gvec4[typ](x, y, z, w) proc `lower`*(x: typ): `upper` = gvec4[typ](x, x, x, x) @@ -934,17 +1255,19 @@ genQuatConstructor(quat, Quat, float32) genQuatConstructor(dquat, DQuat, float64) proc fromAxisAngle*[T](axis: GVec3[T], angle: T): GVec4[T] = + ## Create a quaternion from axis and angle. let a = axis.normalize() s = sin(angle / 2) - [ + gvec4[T]( a.x * s, a.y * s, a.z * s, cos(angle / 2) - ] + ) proc toAxisAngle*[T](q: GVec4[T]): (GVec3[T], T) = + ## Convert a quaternion to axis and angle. let cosAngle = q.w let angle = arccos(cosAngle) * 2.0 var @@ -962,17 +1285,18 @@ proc toAxisAngle*[T](q: GVec4[T]): (GVec3[T], T) = return (axis, angle) proc orthogonal*[T](v: GVec3[T]): GVec3[T] = + ## Returns orthogonal vector to given vector. let v = abs(v) var other: type(v) = if v.x < v.y: if v.x < v.z: - [T(1), 0, 0] # X_AXIS + gvec3(T(1), 0, 0) # X_AXIS else: - [T(0), 0, 1] # Z_AXIS + gvec3(T(0), 0, 1) # Z_AXIS elif v.y < v.z: - [T(0), 1, 0] # Y_AXIS + gvec3(T(0), 1, 0) # Y_AXIS else: - [T(0), 0, 1] # Z_AXIS + gvec3(T(0), 0, 1) # Z_AXIS return cross(v, other) proc fromTwoVectors*[T](a, b: GVec3[T]): GVec4[T] = @@ -989,13 +1313,13 @@ proc fromTwoVectors*[T](a, b: GVec3[T]): GVec4[T] = if (u == -v): # 180 degree rotation around any orthogonal vector let q = normalize(orthogonal(u)) - return [q.x, q.y, q.z, 0] + return gvec4(q.x, q.y, q.z, 0) let half = normalize(u + v) q = cross(u, half) w = dot(u, half) - return [q.x, q.y, q.z, w] + return gvec4(q.x, q.y, q.z, w) proc nlerp*(a: Quat, b: Quat, v: float32): Quat = if dot(a, b) < 0: @@ -1005,6 +1329,7 @@ proc nlerp*(a: Quat, b: Quat, v: float32): Quat = (a * (1.0 - v) + b * v).normalize() proc quat*[T](m: GMat4[T]): GVec4[T] = + ## Create a quaternion from matrix. let m00 = m[0, 0] m01 = m[1, 0] @@ -1039,7 +1364,7 @@ proc quat*[T](m: GMat4[T]): GVec4[T] = q = q * (0.5 / sqrt(t)) if abs(q.length - 1.0) > 0.001: - return [T(0), 0, 0, 1] + return gvec4(T(0), 0, 0, 1) return q @@ -1078,15 +1403,19 @@ proc mat4*[T](q: GVec4[T]): GMat4[T] = result[3, 3] = 1.0 proc rotate*[T](angle: T, axis: GVec3[T]): GMat4[T] = + ## Return a rotation matrix with axis and angle. fromAxisAngle(axis, angle).mat4() proc rotateX*[T](angle: T): GMat4[T] = + ## Return a rotation matrix around X with angle. fromAxisAngle([T(1), 0, 0], angle).mat4() proc rotateY*[T](angle: T): GMat4[T] = + ## Return a rotation matrix around Y with angle. fromAxisAngle([T(0), 1, 0], angle).mat4() proc rotateZ*[T](angle: T): GMat4[T] = + ## Return a rotation matrix around Z with angle. fromAxisAngle([T(0), 0, 1], angle).mat4() when defined(release): diff --git a/tests/bench_rep.nim b/tests/bench_rep.nim new file mode 100644 index 0000000..40ff04d --- /dev/null +++ b/tests/bench_rep.nim @@ -0,0 +1,262 @@ +import benchy + +type + Vec3Obj = object + x, y, z: float32 + + Vec3Arr = array[3, float32] + + Vec3ObjArr = object + arr: array[3, float32] + + Vec3Tuple = tuple[x: float32, y: float32, z: float32] + +proc vec3Obj(x, y, z: float32): Vec3Obj {.inline.} = + Vec3Obj(x: x, y: y, z: z) + +proc vec3Arr(x, y, z: float32): Vec3Arr {.inline.} = + [x, y, z] + +proc vec3ObjArr(x, y, z: float32): Vec3ObjArr {.inline.} = + Vec3ObjArr(arr: [x, y, z]) + +proc vec3Tuple(x, y, z: float32): Vec3Tuple {.inline.} = + (x, y, z) + +timeIt "create vec3Obj", 1000: + var s = newSeq[Vec3Obj](100000) + for i in 0 .. 100000: + s[i] = vec3Obj(i.float32, 0, 0) + keep s + +timeIt "create vec3Arr", 1000: + var s = newSeq[Vec3Arr](100000) + for i in 0 .. 100000: + s[i] = vec3Arr(i.float32, 0, 0) + keep s + +timeIt "create vec3ObjArr", 1000: + var s = newSeq[Vec3ObjArr](100000) + for i in 0 .. 100000: + s[i] = vec3ObjArr(i.float32, 0, 0) + keep s + +timeIt "create vec3Tuple", 1000: + var s = newSeq[Vec3Tuple](100000) + for i in 0 .. 100000: + s[i] = vec3Tuple(i.float32, 0, 0) + keep s + +echo "..." + +proc `[]`(a: Vec3Arr, i: int): float32 {.inline.} = + cast[array[3, float32]](a)[i] + +proc `[]`(a: Vec3Obj, i: int): float32 {.inline.} = + cast[array[3, float32]](a)[i] + +proc `[]`(a: Vec3ObjArr, i: int): float32 {.inline.} = + a.arr[i] + +proc get(a: Vec3Tuple, i: int): float32 {.inline.} = + cast[array[3, float32]](a)[i] + +timeIt "vec3Obj[static]", 1000: + var v = vec3Obj(1, 2, 3) + for i in 0 .. 1000000: + keep v[0] + keep v[1] + keep v[2] + +timeIt "vec3Arr[static]", 1000: + var v = vec3Arr(1, 2, 3) + for i in 0 .. 1000000: + keep v[0] + keep v[1] + keep v[2] + +timeIt "vec3ObjArr[static]", 1000: + var v = vec3ObjArr(1, 2, 3) + for i in 0 .. 1000000: + keep v[0] + keep v[1] + keep v[2] + +timeIt "vec3Tuple[static]", 1000: + var v = vec3Tuple(1, 2, 3) + for i in 0 .. 1000000: + keep v[0] + keep v[1] + keep v[2] + +echo "..." + +timeIt "vec3Obj[]", 1000: + var v = vec3Obj(1, 2, 3) + for i in 0 .. 1000000: + keep v[i mod 3] + +timeIt "vec3Arr[]", 1000: + var v = vec3Arr(1, 2, 3) + for i in 0 .. 1000000: + keep v[i mod 3] + +timeIt "vec3ObjArr[]", 1000: + var v = vec3ObjArr(1, 2, 3) + for i in 0 .. 1000000: + keep v[i mod 3] + +timeIt "vec3Tuple[]", 1000: + var v = vec3Tuple(1, 2, 3) + for i in 0 .. 1000000: + keep v.get(i mod 3) + +echo "..." + +proc `x`(a: Vec3Arr): float32 {.inline.} = a[0] +proc `y`(a: Vec3Arr): float32 {.inline.} = a[1] +proc `z`(a: Vec3Arr): float32 {.inline.} = a[2] + +proc `x`(a: Vec3ObjArr): float32 {.inline.} = a.arr[0] +proc `y`(a: Vec3ObjArr): float32 {.inline.} = a.arr[1] +proc `z`(a: Vec3ObjArr): float32 {.inline.} = a.arr[2] + +timeIt "vec3Obj.xyz", 1000: + var v = vec3Obj(1, 2, 3) + for i in 0 .. 1000000: + keep v.x + keep v.y + keep v.z + +timeIt "vec3Arr.xyz", 1000: + var v = vec3Arr(1, 2, 3) + for i in 0 .. 1000000: + keep v.x + keep v.y + keep v.z + +timeIt "vec3ObjArr.xyz", 1000: + var v = vec3ObjArr(1, 2, 3) + for i in 0 .. 1000000: + keep v.x + keep v.y + keep v.z + +timeIt "vec3Tuple.xyz", 1000: + var v = vec3Tuple(1, 2, 3) + for i in 0 .. 1000000: + keep v.x + keep v.y + keep v.z + +echo "..." + +proc `[]=`(a: var Vec3Obj, i: int, v: float32) {.inline.} = + cast[ptr float32](cast[uint64](a.addr) + i.uint64 * sizeof(float32).uint64)[] = v + +proc `[]=`(a: var Vec3ObjArr, i: int, v: float32) {.inline.} = + a.arr[i] = v + +proc set(a: var Vec3Tuple, i: int, v: float32) {.inline.} = + cast[ptr float32](cast[uint64](a.addr) + i.uint64 * sizeof(float32).uint64)[] = v + + +timeIt "vec3Obj[static]=", 1000: + var v = vec3Obj(1, 2, 3) + for i in 0 .. 1000000: + v[0] = i.float32 + v[1] = i.float32 + v[2] = i.float32 + keep v + +timeIt "vec3Arr[static]=", 1000: + var v = vec3Arr(1, 2, 3) + for i in 0 .. 1000000: + v[0] = i.float32 + v[1] = i.float32 + v[2] = i.float32 + keep v + +timeIt "vec3ObjArr[static]=", 1000: + var v = vec3ObjArr(1, 2, 3) + for i in 0 .. 1000000: + v[0] = i.float32 + v[1] = i.float32 + v[2] = i.float32 + keep v + +timeIt "vec3Tuple[static]=", 1000: + var v = vec3Tuple(1, 2, 3) + for i in 0 .. 1000000: + v[0] = i.float32 + v[1] = i.float32 + v[2] = i.float32 + keep v + +echo "..." + +proc `x=`(a: var Vec3Arr, v: float32) {.inline.} = a[0] = v +proc `y=`(a: var Vec3Arr, v: float32) {.inline.} = a[1] = v +proc `z=`(a: var Vec3Arr, v: float32) {.inline.} = a[2] = v + +proc `x=`(a: var Vec3ObjArr, v: float32) {.inline.} = a.arr[0] = v +proc `y=`(a: var Vec3ObjArr, v: float32) {.inline.} = a.arr[1] = v +proc `z=`(a: var Vec3ObjArr, v: float32) {.inline.} = a.arr[2] = v + +timeIt "vec3Obj.xyz=", 1000: + var v = vec3Obj(1, 2, 3) + for i in 0 .. 1000000: + v.x = i.float32 + v.y = i.float32 + v.z = i.float32 + keep v + +timeIt "vec3Arr.xyz=", 1000: + var v = vec3Arr(1, 2, 3) + for i in 0 .. 1000000: + v.x = i.float32 + v.y = i.float32 + v.z = i.float32 + keep v + +timeIt "vec3ObjArr.xyz=", 1000: + var v = vec3ObjArr(1, 2, 3) + for i in 0 .. 1000000: + v.x = i.float32 + v.y = i.float32 + v.z = i.float32 + keep v + +timeIt "vec3Tuple.xyz=", 1000: + var v = vec3Tuple(1, 2, 3) + for i in 0 .. 1000000: + v.x = i.float32 + v.y = i.float32 + v.z = i.float32 + keep v + +echo "..." + +timeIt "vec3Obj[]=", 1000: + var v = vec3Obj(1, 2, 3) + for i in 0 .. 1000000: + v[i mod 3] = i.float32 + keep v + +timeIt "vec3Arr[]=", 1000: + var v = vec3Arr(1, 2, 3) + for i in 0 .. 1000000: + v[i mod 3] = i.float32 + keep v + +timeIt "vec3ObjArr[]=", 1000: + var v = vec3ObjArr(1, 2, 3) + for i in 0 .. 1000000: + v[i mod 3] = i.float32 + keep v + +timeIt "vec3Tuple[]=", 1000: + var v = vec3Tuple(1, 2, 3) + for i in 0 .. 1000000: + v.set(i mod 3, i.float32) + keep v diff --git a/tests/test.nim b/tests/test.nim index 90e2d10..ab6c964 100644 --- a/tests/test.nim +++ b/tests/test.nim @@ -2,6 +2,7 @@ import random, vmath randomize(1234) + block: # Test ~=. doAssert 1.0 ~= 1.0 @@ -89,6 +90,25 @@ block: doAssert a[0] ~= 1.0 doAssert a[1] ~= 2.0 +block: + # Test position assignment + var + v2 = vec2(0) + v3 = vec3(0) + v4 = vec4(0) + v2[0] = 1.0 + v2[1] = 2.0 + doAssert v2 ~= vec2(1, 2) + v3[0] = 1.0 + v3[1] = 2.0 + v3[2] = 3.0 + doAssert v3 ~= vec3(1, 2, 3) + v4[0] = 1.0 + v4[1] = 2.0 + v4[2] = 3.0 + v4[3] = 4.0 + doAssert v4 ~= vec4(1, 2, 3, 4) + block: # Test vec2 constructor. doAssert vec2(PI, PI) ~= vec2(PI) @@ -170,9 +190,9 @@ block: _ = dvec3(1.0, 2.0, 3.0) _ = dvec4(1.0, 2.0, 3.0, 4.0) - _ = bvec2(true, false) - _ = bvec3(true, false, true) - _ = bvec4(true, false, true, false) + _ = bvec2(true) + _ = bvec3(true) + _ = bvec4(true) _ = ivec2(-1) _ = ivec3(-1) @@ -190,8 +210,28 @@ block: _ = dvec3(1.0) _ = dvec4(1.0) + _ = bvec2() + _ = bvec3() + _ = bvec4() + + _ = ivec2() + _ = ivec3() + _ = ivec4() + + _ = uvec2() + _ = uvec3() + _ = uvec4() + + _ = vec2() + _ = vec3() + _ = vec4() + + _ = dvec2() + _ = dvec3() + _ = dvec4() + block: - # Test basic vector mat constructors. + # Test basic mat constructors. block: let _ = mat2() @@ -276,84 +316,103 @@ block: dvec4(0, 0, 0, 1) ) + block: + var + d2 = dmat2() + d3 = dmat3() + d4 = dmat4() + + d2[0, 0] = 123.123 + d2[1, 1] = 123.123 + + d3[0, 0] = 123.123 + d3[1, 1] = 123.123 + d3[2, 2] = 123.123 + + d4[0, 0] = 123.123 + d4[1, 1] = 123.123 + d4[2, 2] = 123.123 + d4[3, 3] = 123.123 + block: # Test basic mat functions. - doAssert dmat3().transpose() ~= [ - [1.0, 0.0, 0.0], - [0.0, 1.0, 0.0], - [0.0, 0.0, 1.0] - ] - doAssert dmat4().transpose() ~= [ - [1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0], - [0.0, 0.0, 0.0, 1.0] - ] + doAssert dmat3().transpose() ~= dmat3( + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 + ) + doAssert dmat4().transpose() ~= dmat4( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ) - doAssert scale(dvec2(1, 2)) ~= [ - [1.0, 0.0, 0.0], - [0.0, 2.0, 0.0], - [0.0, 0.0, 1.0] - ] - doAssert scale(dvec3(2, 2, 3)) ~= [ - [2.0, 0.0, 0.0, 0.0], - [0.0, 2.0, 0.0, 0.0], - [0.0, 0.0, 3.0, 0.0], - [0.0, 0.0, 0.0, 1.0] - ] + doAssert scale(dvec2(1, 2)) ~= dmat3( + 1.0, 0.0, 0.0, + 0.0, 2.0, 0.0, + 0.0, 0.0, 1.0 + ) + doAssert scale(dvec3(2, 2, 3)) ~= dmat4( + 2.0, 0.0, 0.0, 0.0, + 0.0, 2.0, 0.0, 0.0, + 0.0, 0.0, 3.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ) - doAssert translate(dvec2(1, 2)) ~= [ - [1.0, 0.0, 0.0], - [0.0, 1.0, 0.0], - [1.0, 2.0, 1.0] - ] - doAssert translate(dvec3(1, 2, 3)) ~= [ - [1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0], - [1.0, 2.0, 3.0, 1.0] - ] + doAssert translate(dvec2(1, 2)) ~= dmat3( + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 1.0, 2.0, 1.0 + ) + doAssert translate(dvec3(1, 2, 3)) ~= dmat4( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 1.0, 2.0, 3.0, 1.0 + ) - doAssert rotate(1.0) ~= [ - [0.5403023058681398, -0.8414709848078965, 0.0], - [0.8414709848078965, 0.5403023058681398, 0.0], - [0.0, 0.0, 1.0] - ] + doAssert rotate(1.0) ~= dmat3( + 0.5403023058681398, -0.8414709848078965, 0.0, + 0.8414709848078965, 0.5403023058681398, 0.0, + 0.0, 0.0, 1.0 + ) - doAssert scale(dvec2(2)) ~= [ - [2.0, 0.0, 0.0], - [0.0, 2.0, 0.0], - [0.0, 0.0, 1.0] - ] - doAssert scale(dvec3(2)) ~= [ - [2.0, 0.0, 0.0, 0.0], - [0.0, 2.0, 0.0, 0.0], - [0.0, 0.0, 2.0, 0.0], - [0.0, 0.0, 0.0, 1.0] - ] - doAssert translate(dvec2(2)) ~= [ - [1.0, 0.0, 0.0], - [0.0, 1.0, 0.0], - [2.0, 2.0, 1.0] - ] - doAssert translate(dvec3(2)) ~= [ - [1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0], - [2.0, 2.0, 2.0, 1.0] - ] + doAssert scale(dvec2(2)) ~= dmat3( + 2.0, 0.0, 0.0, + 0.0, 2.0, 0.0, + 0.0, 0.0, 1.0 + ) + doAssert scale(dvec3(2)) ~= dmat4( + 2.0, 0.0, 0.0, 0.0, + 0.0, 2.0, 0.0, 0.0, + 0.0, 0.0, 2.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ) - doAssert rotate(1.0).inverse() ~= [ - [0.5403023058681398, 0.8414709848078965, -0.0], - [-0.8414709848078965, 0.5403023058681398, -0.0], - [0.0, -0.0, 1.0] - ] - doAssert rotate(1.0, dvec3(1, 0, 0)).inverse() ~= [ - [1.0, 0.0, 0.0, 0.0], - [-0.0, 0.5403022766113281, 0.8414710164070129, 0.0], - [0.0, -0.8414710164070129, 0.5403022766113281, 0.0], - [0.0, 0.0, 0.0, 1.0] - ] + doAssert translate(dvec2(2)) ~= dmat3( + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 2.0, 2.0, 1.0 + ) + doAssert translate(dvec3(2)) ~= dmat4( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 2.0, 2.0, 2.0, 1.0 + ) + + doAssert rotate(1.0).inverse() ~= dmat3( + 0.5403023058681398, 0.8414709848078965, -0.0, + -0.8414709848078965, 0.5403023058681398, -0.0, + 0.0, -0.0, 1.0 + ) + doAssert rotate(1.0, dvec3(1, 0, 0)).inverse() ~= dmat4( + 1.0, 0.0, 0.0, 0.0, + -0.0, 0.5403022766113281, 0.8414710164070129, 0.0, + 0.0, -0.8414710164070129, 0.5403022766113281, 0.0, + 0.0, 0.0, 0.0, 1.0 + ) doAssert translate(vec2(1, 2)).pos == vec2(1, 2) @@ -543,3 +602,5 @@ block: b = vec3(rand(2.0)-0.5, rand(2.0)-0.5, rand(2.0)-0.5).normalize() q = fromTwoVectors(a, b) doAssert q.mat4 * a ~= b + +echo "test finished successfully"