From 2b8720d7e441bc0d305775a95e7c64cae52dcf7d Mon Sep 17 00:00:00 2001 From: Nimaoth Date: Sat, 20 May 2023 23:52:06 +0200 Subject: [PATCH 1/3] made vectors in vmathObjBased work in js backend --- src/vmath.nim | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/vmath.nim b/src/vmath.nim index b1bb102..5c474d7 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -151,18 +151,55 @@ elif defined(vmathObjBased): 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] + when not defined(js): + 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[ByteAddress](a.addr) + i * sizeof(T))[] = v + template `[]=`*[T](a: var GVec2[T], i: int, v: T) = + cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v + + template `[]=`*[T](a: var GVec3[T], i: int, v: T) = + cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v + + template `[]=`*[T](a: var GVec4[T], i: int, v: T) = + cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v + else: + template `[]`*[T](a: GVec2[T], i: static[int]): T = + when i == 0: a.x + elif i == 1: a.y + else: {.error.} + + template `[]`*[T](a: GVec3[T], i: static[int]): T = + when i == 0: a.x + elif i == 1: a.y + elif i == 2: a.z + else: {.error.} + + template `[]`*[T](a: GVec4[T], i: static[int]): T = + when i == 0: a.x + elif i == 1: a.y + elif i == 2: a.z + elif i == 3: a.w + else: {.error.} + + template `[]=`*[T](a: var GVec2[T], i: int, v: T) = + when i == 0: a.x = v + elif i == 1: a.y = v + else: {.error.} template `[]=`*[T](a: var GVec3[T], i: int, v: T) = - cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v + when i == 0: a.x = v + elif i == 1: a.y = v + elif i == 2: a.z = v + else: {.error.} template `[]=`*[T](a: var GVec4[T], i: int, v: T) = - cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v + when i == 0: a.x = v + elif i == 1: a.y = v + elif i == 2: a.z = v + elif i == 3: a.w = v + else: {.error.} type GMat2*[T] {.bycopy.} = object From ae7da31f9a545989a56e896e3f992c70cb49ff59 Mon Sep 17 00:00:00 2001 From: Nimaoth Date: Sun, 21 May 2023 00:59:59 +0200 Subject: [PATCH 2/3] made obj based work in browser --- src/vmath.nim | 137 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 55 deletions(-) diff --git a/src/vmath.nim b/src/vmath.nim index 5c474d7..130accd 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -31,6 +31,7 @@ float64 double DVec2 DVec3 DVec4 DMat3 DMat4 DQuat ]## import macros, math, strutils +import std/[genasts] export math except isNan {.push inline.} @@ -151,55 +152,58 @@ elif defined(vmathObjBased): template gvec4*[T](mx, my, mz, mw: T): GVec4[T] = GVec4[T](x: mx, y: my, z: mz, w: mw) + macro genStaticReadAccess(a: typed, index: static[int]): untyped = + if index < a.getType[2].len: + return nnkDotExpr.newTree(a, a.getType[2][index]) + error("Index " & $index & " is out of range for type " & a.getType.repr, a) + + macro genReadAccess(a: typed, index: untyped, default: untyped): untyped = + var branch = nnkCaseStmt.newTree(index) + for i, member in a.getType[2]: + branch.add nnkOfBranch.newTree(i.newLit, nnkDotExpr.newTree(a, member)) + branch.add nnkElse.newTree(default) + return branch + + macro genStaticWriteAccess(a: typed, index: static[int], v: untyped): untyped = + if index < a.getType[2].len: + return genAst(a, member=a.getType[2][index], v): + a.member = v + error("Index " & $index & " is out of range for type " & a.getType.repr, a) + + macro genWriteAccess(a: typed, index: typed, v: typed): untyped = + var branch = nnkCaseStmt.newTree(index) + for i, member in a.getType[2]: + let assignment = genAst(a, member, v): + a.member = v + branch.add nnkOfBranch.newTree(i.newLit, assignment) + branch.add nnkElse.newTree(nnkStmtList.newTree()) + return branch + + template `[]`*[T](a: GVec2[T], i: static[int]): T = genStaticReadAccess(a, i) + template `[]`*[T](a: GVec3[T], i: static[int]): T = genStaticReadAccess(a, i) + template `[]`*[T](a: GVec4[T], i: static[int]): T = genStaticReadAccess(a, i) + + template `[]=`*[T](a: var GVec2[T], i: static[int], v: T) = genStaticWriteAccess(a, i, v) + template `[]=`*[T](a: var GVec3[T], i: static[int], v: T) = genStaticWriteAccess(a, i, v) + template `[]=`*[T](a: var GVec4[T], i: static[int], v: T) = genStaticWriteAccess(a, i, v) + when not defined(js): 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[ByteAddress](a.addr) + i * sizeof(T))[] = v - - template `[]=`*[T](a: var GVec3[T], i: int, v: T) = - cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v + template `[]=`*[T](a: var GVec2[T], i: int, v: T) = cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v + template `[]=`*[T](a: var GVec3[T], i: int, v: T) = cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v + template `[]=`*[T](a: var GVec4[T], i: int, v: T) = cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v - template `[]=`*[T](a: var GVec4[T], i: int, v: T) = - cast[ptr T](cast[ByteAddress](a.addr) + i * sizeof(T))[] = v else: - template `[]`*[T](a: GVec2[T], i: static[int]): T = - when i == 0: a.x - elif i == 1: a.y - else: {.error.} - - template `[]`*[T](a: GVec3[T], i: static[int]): T = - when i == 0: a.x - elif i == 1: a.y - elif i == 2: a.z - else: {.error.} - - template `[]`*[T](a: GVec4[T], i: static[int]): T = - when i == 0: a.x - elif i == 1: a.y - elif i == 2: a.z - elif i == 3: a.w - else: {.error.} - - template `[]=`*[T](a: var GVec2[T], i: int, v: T) = - when i == 0: a.x = v - elif i == 1: a.y = v - else: {.error.} - - template `[]=`*[T](a: var GVec3[T], i: int, v: T) = - when i == 0: a.x = v - elif i == 1: a.y = v - elif i == 2: a.z = v - else: {.error.} - - template `[]=`*[T](a: var GVec4[T], i: int, v: T) = - when i == 0: a.x = v - elif i == 1: a.y = v - elif i == 2: a.z = v - elif i == 3: a.w = v - else: {.error.} + template `[]`*[T](a: GVec2[T], i: int): T = genReadAccess(a, i, T.default) + template `[]`*[T](a: GVec3[T], i: int): T = genReadAccess(a, i, T.default) + template `[]`*[T](a: GVec4[T], i: int): T = genReadAccess(a, i, T.default) + + template `[]=`*[T](a: var GVec2[T], i: int, v: T) = genWriteAccess(a, i, v) + template `[]=`*[T](a: var GVec3[T], i: int, v: T) = genWriteAccess(a, i, v) + template `[]=`*[T](a: var GVec4[T], i: int, v: T) = genWriteAccess(a, i, v) type GMat2*[T] {.bycopy.} = object @@ -242,23 +246,45 @@ elif defined(vmathObjBased): 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: GMat2[T], i, j: static[int]): T = genStaticReadAccess(a, (i * 2) + j) + template `[]`*[T](a: GMat3[T], i, j: static[int]): T = genStaticReadAccess(a, (i * 3) + j) + template `[]`*[T](a: GMat4[T], i, j: static[int]): T = genStaticReadAccess(a, (i * 4) + j, 0) - template `[]`*[T](a: GMat3[T], i, j: int): T = - cast[array[9, T]](a)[i * 3 + j] + template `[]=`*[T](a: var GMat2[T], i, j: static[int], v: T) = genStaticWriteAccess(a, (i * 2) + j, v) + template `[]=`*[T](a: var GMat3[T], i, j: static[int], v: T) = genStaticWriteAccess(a, (i * 3) + j, v) + template `[]=`*[T](a: var GMat4[T], i, j: static[int], v: T) = genStaticWriteAccess(a, (i * 4) + j, v) - template `[]`*[T](a: GMat4[T], i, j: int): T = - cast[array[16, T]](a)[i * 4 + j] + when not defined(js): + 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[ByteAddress](a.addr) + (i * 2 + j) * sizeof(T))[] = v + template `[]=`*[T](a: var GMat2[T], i, j: int, v: T) = cast[ptr T](cast[ByteAddress](a.addr) + (i * 2 + j) * sizeof(T))[] = v + template `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = cast[ptr T](cast[ByteAddress](a.addr) + (i * 3 + j) * sizeof(T))[] = v + template `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = cast[ptr T](cast[ByteAddress](a.addr) + (i * 4 + j) * sizeof(T))[] = v - template `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = - cast[ptr T](cast[ByteAddress](a.addr) + (i * 3 + j) * sizeof(T))[] = v - - template `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = - cast[ptr T](cast[ByteAddress](a.addr) + (i * 4 + j) * sizeof(T))[] = v + else: + template `[]`*[T](a: GMat2[T], i, j: int): T = genReadAccess(a, (i * 2) + j, T.default) + template `[]`*[T](a: GMat3[T], i, j: int): T = genReadAccess(a, (i * 3) + j, T.default) + template `[]`*[T](a: GMat4[T], i, j: int): T = genReadAccess(a, (i * 4) + j, T.default) + + template `[]=`*[T](a: var GMat2[T], i, j: int, v: T) = genWriteAccess(a, (i * 2) + j, v) + template `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = genWriteAccess(a, (i * 3) + j, v) + template `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = genWriteAccess(a, (i * 4) + j, v) + + var foo = gmat2(1, 2, 3, 4) + echo foo[0, 0] + echo foo[0, 1] + echo foo[1, 0] + echo foo[1, 1] + foo[0, 0] = 5 + foo[0, 1] = 6 + foo[1, 0] = 7 + foo[1, 1] = 8 + echo foo[0, 0] + echo foo[0, 1] + echo foo[1, 0] + echo foo[1, 1] template `[]`*[T](a: GMat2[T], i: int): GVec2[T] = gvec2[T]( @@ -282,6 +308,7 @@ elif defined(vmathObjBased): ) elif true or defined(vmathObjArrayBased): + type GVec2*[T] = object arr: array[2, T] From 661bdaac7546e16d087f066adfeb6ea7590106b4 Mon Sep 17 00:00:00 2001 From: Nimaoth Date: Sun, 21 May 2023 14:09:27 +0200 Subject: [PATCH 3/3] fixed bug, added tests --- src/vmath.nim | 16 +--------------- tests/test.nim | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/vmath.nim b/src/vmath.nim index 130accd..4c79c14 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -248,7 +248,7 @@ elif defined(vmathObjBased): template `[]`*[T](a: GMat2[T], i, j: static[int]): T = genStaticReadAccess(a, (i * 2) + j) template `[]`*[T](a: GMat3[T], i, j: static[int]): T = genStaticReadAccess(a, (i * 3) + j) - template `[]`*[T](a: GMat4[T], i, j: static[int]): T = genStaticReadAccess(a, (i * 4) + j, 0) + template `[]`*[T](a: GMat4[T], i, j: static[int]): T = genStaticReadAccess(a, (i * 4) + j) template `[]=`*[T](a: var GMat2[T], i, j: static[int], v: T) = genStaticWriteAccess(a, (i * 2) + j, v) template `[]=`*[T](a: var GMat3[T], i, j: static[int], v: T) = genStaticWriteAccess(a, (i * 3) + j, v) @@ -272,20 +272,6 @@ elif defined(vmathObjBased): template `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = genWriteAccess(a, (i * 3) + j, v) template `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = genWriteAccess(a, (i * 4) + j, v) - var foo = gmat2(1, 2, 3, 4) - echo foo[0, 0] - echo foo[0, 1] - echo foo[1, 0] - echo foo[1, 1] - foo[0, 0] = 5 - foo[0, 1] = 6 - foo[1, 0] = 7 - foo[1, 1] = 8 - echo foo[0, 0] - echo foo[0, 1] - echo foo[1, 0] - echo foo[1, 1] - template `[]`*[T](a: GMat2[T], i: int): GVec2[T] = gvec2[T]( a[i, 0], diff --git a/tests/test.nim b/tests/test.nim index ffba8db..c5fef92 100644 --- a/tests/test.nim +++ b/tests/test.nim @@ -1155,4 +1155,37 @@ block: else: doAssert abs(angleBetween(a.y, b.y - b.z)) < 0.001 +block: + # Test vector and matrix [] accessors + + # Test matrix + var m = gmat2(1, 2, 3, 4) + + doAssert m[0, 0] == 1 + doAssert m[0, 1] == 2 + doAssert m[1, 0] == 3 + doAssert m[1, 1] == 4 + + m[0, 0] = 5 + m[0, 1] = 6 + m[1, 0] = 7 + m[1, 1] = 8 + + doAssert m[0, 0] == 5 + doAssert m[0, 1] == 6 + doAssert m[1, 0] == 7 + doAssert m[1, 1] == 8 + + # Test vector + var v = gvec2(1, 2) + + doAssert v[0] == 1 + doAssert v[1] == 2 + + v[0] = 5 + v[1] = 6 + + doAssert v[0] == 5 + doAssert v[1] == 6 + echo "test finished successfully"