diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b4e2451..2efb731 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,3 +28,7 @@ jobs: run: nim r -d:vmathArrayBased tests/tests.nim - name: Test JavaScript run: nim js -r tests/tests.nim + - name: Test JavaScript object based + run: nim js -r -d:vmathObjBased tests/tests.nim + - name: Test JavaScript array based + run: nim js -r -d:vmathArrayBased tests/tests.nim diff --git a/src/vmath.nim b/src/vmath.nim index e0036e7..6a98d29 100644 --- a/src/vmath.nim +++ b/src/vmath.nim @@ -123,14 +123,19 @@ when defined(vmathArrayBased): 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[ByteAddress](a.addr) + (i * 2 + j) * sizeof(T))[] = v + when defined(js): + template `[]=`*[T](a: var GMat2[T], i, j: int, v: T) = a[i][j] = v + template `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = a[i][j] = v + template `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = a[i][j] = v + else: + 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 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 GMat4[T], i, j: int, v: T) = + cast[ptr T](cast[ByteAddress](a.addr) + (i * 4 + j) * sizeof(T))[] = v elif defined(vmathObjBased): type @@ -152,18 +157,61 @@ 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 defined(js): + proc `[]`*[T](a: GVec2[T], i: int): T = + case i + of 0: a.x + of 1: a.y + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]`*[T](a: GVec3[T], i: int): T = + case i + of 0: a.x + of 1: a.y + of 2: a.z + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]`*[T](a: GVec4[T], i: int): T = + case i + of 0: a.x + of 1: a.y + of 2: a.z + of 3: a.w + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]=`*[T](a: var GVec2[T], i: int, v: T) = + case i + of 0: a.x = v + of 1: a.y = v + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]=`*[T](a: var GVec3[T], i: int, v: T) = + case i + of 0: a.x = v + of 1: a.y = v + of 2: a.z = v + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]=`*[T](a: var GVec4[T], i: int, v: T) = + case i + of 0: a.x = v + of 1: a.y = v + of 2: a.z = v + of 3: a.w = v + else: raise newException(IndexDefect, "index out of bounds") + else: + 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 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 type GMat2*[T] {.bycopy.} = object @@ -206,23 +254,106 @@ 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] + when defined(js): + proc `[]`*[T](a: GMat2[T], i, j: int): T = + case i * 2 + j + of 0: a.m00 + of 1: a.m01 + of 2: a.m10 + of 3: a.m11 + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]`*[T](a: GMat3[T], i, j: int): T = + case i * 3 + j + of 0: a.m00 + of 1: a.m01 + of 2: a.m02 + of 3: a.m10 + of 4: a.m11 + of 5: a.m12 + of 6: a.m20 + of 7: a.m21 + of 8: a.m22 + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]`*[T](a: GMat4[T], i, j: int): T = + case i * 4 + j + of 0: a.m00 + of 1: a.m01 + of 2: a.m02 + of 3: a.m03 + of 4: a.m10 + of 5: a.m11 + of 6: a.m12 + of 7: a.m13 + of 8: a.m20 + of 9: a.m21 + of 10: a.m22 + of 11: a.m23 + of 12: a.m30 + of 13: a.m31 + of 14: a.m32 + of 15: a.m33 + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]=`*[T](a: var GMat2[T], i, j: int, v: T) = + case i * 2 + j + of 0: a.m00 = v + of 1: a.m01 = v + of 2: a.m10 = v + of 3: a.m11 = v + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]=`*[T](a: var GMat3[T], i, j: int, v: T) = + case i * 3 + j + of 0: a.m00 = v + of 1: a.m01 = v + of 2: a.m02 = v + of 3: a.m10 = v + of 4: a.m11 = v + of 5: a.m12 = v + of 6: a.m20 = v + of 7: a.m21 = v + of 8: a.m22 = v + else: raise newException(IndexDefect, "index out of bounds") + + proc `[]=`*[T](a: var GMat4[T], i, j: int, v: T) = + case i * 4 + j + of 0: a.m00 = v + of 1: a.m01 = v + of 2: a.m02 = v + of 3: a.m03 = v + of 4: a.m10 = v + of 5: a.m11 = v + of 6: a.m12 = v + of 7: a.m13 = v + of 8: a.m20 = v + of 9: a.m21 = v + of 10: a.m22 = v + of 11: a.m23 = v + of 12: a.m30 = v + of 13: a.m31 = v + of 14: a.m32 = v + of 15: a.m33 = v + else: raise newException(IndexDefect, "index out of bounds") + else: + 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: 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: 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 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 GMat4[T], i, j: int, v: T) = + cast[ptr T](cast[ByteAddress](a.addr) + (i * 4 + j) * sizeof(T))[] = v template `[]`*[T](a: GMat2[T], i: int): GVec2[T] = gvec2[T]( diff --git a/tests/tests.nim b/tests/tests.nim index 9382c52..56e02df 100644 --- a/tests/tests.nim +++ b/tests/tests.nim @@ -128,6 +128,32 @@ suite "vector memory layout": v4[0] = 1.0; v4[1] = 2.0; v4[2] = 3.0; v4[3] = 4.0 check v4 ~= vec4(1, 2, 3, 4) + test "vec indexed access across scalar types": + var bv = bvec4(false) + for i in 0 .. 3: + bv[i] = i mod 2 == 0 + check bv == bvec4(true, false, true, false) + + var iv = ivec4(0) + for i in 0 .. 3: + iv[i] = int32(-i - 1) + check iv == ivec4(-1, -2, -3, -4) + + var uv = uvec4(0) + for i in 0 .. 3: + uv[i] = uint32(i + 10) + check uv == uvec4(10, 11, 12, 13) + + var fv = vec4(0) + for i in 0 .. 3: + fv[i] = float32(i) + 0.5'f32 + check fv == vec4(0.5, 1.5, 2.5, 3.5) + + var dv = dvec4(0) + for i in 0 .. 3: + dv[i] = float64(i) + 0.25 + check dv == dvec4(0.25, 1.25, 2.25, 3.25) + suite "mat2 memory layout and element access": test "mat2 cast to flat array is column-major": when not defined(js): @@ -406,6 +432,37 @@ suite "mat4 memory layout and element access": check fromScalars ~= fromVecs check fromScalars ~= mat4() + test "mat indexed access across float types": + var m2 = mat2() + var m2Value = 1.0'f32 + for i in 0 .. 1: + for j in 0 .. 1: + m2[i, j] = m2Value + m2Value += 1.0'f32 + check m2[0, 0] == 1.0'f32 + check m2[0, 1] == 2.0'f32 + check m2[1] == vec2(3, 4) + + var m3 = mat3() + var m3Value = 1.0'f32 + for i in 0 .. 2: + for j in 0 .. 2: + m3[i, j] = m3Value + m3Value += 1.0'f32 + check m3[0, 0] == 1.0'f32 + check m3[2, 2] == 9.0'f32 + check m3[2] == vec3(7, 8, 9) + + var dm4 = dmat4() + var dm4Value = 0.5 + for i in 0 .. 3: + for j in 0 .. 3: + dm4[i, j] = dm4Value + dm4Value += 0.5 + check dm4[0, 0] == 0.5 + check dm4[3, 3] == 8.0 + check dm4[2] == dvec4(4.5, 5.0, 5.5, 6.0) + suite "mat4 operations": let a = when defined(js):