Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made array based accessor ([] and []=) work in javascript with vmathObjBased #67

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 72 additions & 22 deletions src/vmath.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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.}
Expand Down Expand Up @@ -151,18 +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)

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]
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 GVec4[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
else:
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 GVec4[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) = 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
Expand Down Expand Up @@ -205,23 +246,31 @@ 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)

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
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 GMat4[T], i, j: int, v: T) =
cast[ptr T](cast[ByteAddress](a.addr) + (i * 4 + j) * sizeof(T))[] = v
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)

template `[]`*[T](a: GMat2[T], i: int): GVec2[T] =
gvec2[T](
Expand All @@ -245,6 +294,7 @@ elif defined(vmathObjBased):
)

elif true or defined(vmathObjArrayBased):

type
GVec2*[T] = object
arr: array[2, T]
Expand Down
33 changes: 33 additions & 0 deletions tests/test.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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"