Add Swizzle to all Vecs. (#39)
* Add swizzle based on macro. * More constructors. * Make it work with shady. * Morepretty. * Add ray tracer output. * Better typePrefix that works with all vector layouts.
This commit is contained in:
parent
9196bbfe81
commit
f711a5ff6d
178
src/vmath.nim
178
src/vmath.nim
|
@ -4,7 +4,7 @@
|
||||||
## default: ObjArray based
|
## default: ObjArray based
|
||||||
##
|
##
|
||||||
|
|
||||||
import math, strutils
|
import macros, math, strutils
|
||||||
export math except isNan
|
export math except isNan
|
||||||
|
|
||||||
{.push inline.}
|
{.push inline.}
|
||||||
|
@ -230,13 +230,13 @@ elif true or defined(vmathObjArrayBased):
|
||||||
GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T]
|
GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T]
|
||||||
|
|
||||||
template gvec2*[T](x, y: T): GVec2[T] =
|
template gvec2*[T](x, y: T): GVec2[T] =
|
||||||
GVec2[T](arr:[T(x), T(y)])
|
GVec2[T](arr: [T(x), T(y)])
|
||||||
|
|
||||||
template gvec3*[T](x, y, z: T): GVec3[T] =
|
template gvec3*[T](x, y, z: T): GVec3[T] =
|
||||||
GVec3[T](arr:[T(x), T(y), T(z)])
|
GVec3[T](arr: [T(x), T(y), T(z)])
|
||||||
|
|
||||||
template gvec4*[T](x, y, z, w: T): GVec4[T] =
|
template gvec4*[T](x, y, z, w: T): GVec4[T] =
|
||||||
GVec4[T](arr:[T(x), T(y), T(z), T(w)])
|
GVec4[T](arr: [T(x), T(y), T(z), T(w)])
|
||||||
|
|
||||||
template x*[T](a: var GVec2[T]): var T = a.arr[0]
|
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 y*[T](a: var GVec2[T]): var T = a.arr[1]
|
||||||
|
@ -436,6 +436,9 @@ proc isNan*(x: SomeFloat): bool =
|
||||||
## Returns true if number is a NaN.
|
## Returns true if number is a NaN.
|
||||||
x != 0.0 and (x != x or x * 0.5 == x)
|
x != 0.0 and (x != x or x * 0.5 == x)
|
||||||
|
|
||||||
|
template lowerType(a: typed): string =
|
||||||
|
($type(a)).toLowerAscii()
|
||||||
|
|
||||||
template genConstructor(lower, upper, typ: untyped) =
|
template genConstructor(lower, upper, typ: untyped) =
|
||||||
|
|
||||||
proc `lower 2`*(): `upper 2` = gvec2[typ](typ(0), typ(0))
|
proc `lower 2`*(): `upper 2` = gvec2[typ](typ(0), typ(0))
|
||||||
|
@ -457,17 +460,20 @@ template genConstructor(lower, upper, typ: untyped) =
|
||||||
proc `lower 4`*[T](x: GVec4[T]): `upper 4` =
|
proc `lower 4`*[T](x: GVec4[T]): `upper 4` =
|
||||||
gvec4[typ](typ(x[0]), typ(x[1]), typ(x[2]), typ(x[3]))
|
gvec4[typ](typ(x[0]), typ(x[1]), typ(x[2]), typ(x[3]))
|
||||||
|
|
||||||
proc `lower 3`*[T](x: GVec2[T]): `upper 3` =
|
proc `lower 3`*[T](x: GVec2[T], z: T = 0): `upper 3` =
|
||||||
gvec3[typ](typ(x[0]), typ(x[1]), 0)
|
gvec3[typ](typ(x[0]), typ(x[1]), z)
|
||||||
proc `lower 4`*[T](x: GVec3[T]): `upper 4` =
|
proc `lower 4`*[T](x: GVec3[T], w: T = 0): `upper 4` =
|
||||||
gvec4[typ](typ(x[0]), typ(x[1]), typ(x[2]), 0)
|
gvec4[typ](typ(x[0]), typ(x[1]), typ(x[2]), w)
|
||||||
|
|
||||||
|
proc `lower 4`*[T](a, b: GVec2[T]): `upper 4` =
|
||||||
|
gvec4[typ](typ(a[0]), typ(a[1]), typ(b[0]), typ(b[1]))
|
||||||
|
|
||||||
proc `$`*(a: `upper 2`): string =
|
proc `$`*(a: `upper 2`): string =
|
||||||
($type(a)).toLowerAscii() & "(" & $a.x & ", " & $a.y & ")"
|
lowerType(a) & "(" & $a.x & ", " & $a.y & ")"
|
||||||
proc `$`*(a: `upper 3`): string =
|
proc `$`*(a: `upper 3`): string =
|
||||||
($type(a)).toLowerAscii() & "(" & $a.x & ", " & $a.y & ", " & $a.z & ")"
|
lowerType(a) & "(" & $a.x & ", " & $a.y & ", " & $a.z & ")"
|
||||||
proc `$`*(a: `upper 4`): string =
|
proc `$`*(a: `upper 4`): string =
|
||||||
($type(a)).toLowerAscii() & "(" & $a.x & ", " & $a.y & ", " & $a.z & ", " & $a.w & ")"
|
lowerType(a) & "(" & $a.x & ", " & $a.y & ", " & $a.z & ", " & $a.w & ")"
|
||||||
|
|
||||||
genConstructor(bvec, BVec, bool)
|
genConstructor(bvec, BVec, bool)
|
||||||
genConstructor(ivec, IVec, int32)
|
genConstructor(ivec, IVec, int32)
|
||||||
|
@ -475,40 +481,124 @@ genConstructor(uvec, UVec, uint32)
|
||||||
genConstructor(vec, Vec, float32)
|
genConstructor(vec, Vec, float32)
|
||||||
genConstructor(dvec, DVec, float64)
|
genConstructor(dvec, DVec, float64)
|
||||||
|
|
||||||
proc xy*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.x, a.y)
|
{.experimental: "dotOperators".}
|
||||||
proc xz*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.x, a.z)
|
proc num(letter: char, fields: NimNode): int =
|
||||||
proc yx*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.y, a.x)
|
## Given a swizzle character gives back the location number.
|
||||||
proc yz*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.y, a.z)
|
case letter:
|
||||||
proc zx*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.z, a.x)
|
of 'x', 'r', 's': 0
|
||||||
proc zy*[T](a: GVec234[T]): GVec2[T] = gvec2[T](a.z, a.y)
|
of 'y', 'g', 't': 1
|
||||||
|
of 'z', 'b', 'p': 2
|
||||||
|
of 'w', 'a', 'q': 3
|
||||||
|
else:
|
||||||
|
error "invalid swizzle character: " & letter, fields
|
||||||
|
quit()
|
||||||
|
|
||||||
proc xxx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.x, a.x)
|
proc typePrefix(node: NimNode): string =
|
||||||
proc xxy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.x, a.y)
|
## Given a node of type GVec234 gives its prefix type.
|
||||||
proc xxz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.x, a.z)
|
## IVec2 -> "i", DVec4 -> "d", Vec3 -> ""
|
||||||
proc xyx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.y, a.x)
|
let typeName =
|
||||||
proc xyy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.y, a.y)
|
when defined(vmathArrayBased):
|
||||||
proc xyz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.y, a.z)
|
node.getType()[2].repr
|
||||||
proc xzx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.z, a.x)
|
elif defined(vmathObjBased):
|
||||||
proc xzy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.z, a.y)
|
node.getType()[2][0].getType().repr
|
||||||
proc xzz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.x, a.z, a.z)
|
elif true or defined(vmathObjArrayBased):
|
||||||
proc yxx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.x, a.x)
|
node.getType()[2][0].getType()[2].repr
|
||||||
proc yxy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.x, a.y)
|
case typeName:
|
||||||
proc yxz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.x, a.z)
|
of "bool": "b"
|
||||||
proc yyx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.y, a.x)
|
of "int32": "i"
|
||||||
proc yyy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.y, a.y)
|
of "uint32": "u"
|
||||||
proc yyz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.y, a.z)
|
of "float32": ""
|
||||||
proc yzx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.z, a.x)
|
of "float", "float64": "d"
|
||||||
proc yzy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.z, a.y)
|
else:
|
||||||
proc yzz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.y, a.z, a.z)
|
error "invalid vector type: " & typeName, node
|
||||||
proc zxx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.x, a.x)
|
quit()
|
||||||
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)
|
macro `.`*(v: GVec234, fields: untyped): untyped =
|
||||||
proc zyx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.y, a.x)
|
## Adds support for swizzle getter.
|
||||||
proc zyy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.y, a.y)
|
## x y z w
|
||||||
proc zyz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.y, a.z)
|
## r g b a
|
||||||
proc zzx*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.z, a.x)
|
## s t p q
|
||||||
proc zzy*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.z, a.y)
|
## v.xyz, v.xxx, v.zyx ...
|
||||||
proc zzz*[T](a: GVec34[T]): GVec3[T] = gvec3[T](a.z, a.z, a.z)
|
## v.rgb, v.rrr, v.bgr ...
|
||||||
|
## v.stp, v.sss, v.pts ...
|
||||||
|
let swizzle = fields.repr
|
||||||
|
let vec = ident(typePrefix(v) & "vec" & $swizzle.len)
|
||||||
|
if swizzle.len == 1:
|
||||||
|
let a = num(swizzle[0], fields)
|
||||||
|
result = quote do:
|
||||||
|
`v`[`a`]
|
||||||
|
elif swizzle.len == 2:
|
||||||
|
let
|
||||||
|
a = num(swizzle[0], fields)
|
||||||
|
b = num(swizzle[1], fields)
|
||||||
|
result = quote do:
|
||||||
|
`vec`(`v`[`a`], `v`[`b`])
|
||||||
|
elif swizzle.len == 3:
|
||||||
|
let
|
||||||
|
a = num(swizzle[0], fields)
|
||||||
|
b = num(swizzle[1], fields)
|
||||||
|
c = num(swizzle[2], fields)
|
||||||
|
result = quote do:
|
||||||
|
`vec`(`v`[`a`], `v`[`b`], `v`[`c`])
|
||||||
|
elif swizzle.len == 4:
|
||||||
|
let
|
||||||
|
a = num(swizzle[0], fields)
|
||||||
|
b = num(swizzle[1], fields)
|
||||||
|
c = num(swizzle[2], fields)
|
||||||
|
d = num(swizzle[3], fields)
|
||||||
|
result = quote do:
|
||||||
|
`vec`(`v`[`a`], `v`[`b`], `v`[`c`], `v`[`d`])
|
||||||
|
else:
|
||||||
|
error "invalid number of swizzle characters: " & swizzle, fields
|
||||||
|
|
||||||
|
macro `.=`*(v: GVec234, fields: untyped, e: untyped): untyped =
|
||||||
|
## Adds support for swizzle setter.
|
||||||
|
## x y z w
|
||||||
|
## r g b a
|
||||||
|
## s t p q
|
||||||
|
## v.xyz, v.xxx, v.zyx ...
|
||||||
|
## v.rgb, v.rrr, v.bgr ...
|
||||||
|
## v.stp, v.sss, v.pts ...
|
||||||
|
let swizzle = fields.repr
|
||||||
|
if swizzle.len == 1:
|
||||||
|
let a = num(swizzle[0], fields)
|
||||||
|
result = quote do:
|
||||||
|
`v`[`a`] = `e`
|
||||||
|
elif swizzle.len == 2:
|
||||||
|
let
|
||||||
|
a = num(swizzle[0], fields)
|
||||||
|
b = num(swizzle[1], fields)
|
||||||
|
result = quote do:
|
||||||
|
block:
|
||||||
|
let tmp = `e`
|
||||||
|
`v`[`a`] = tmp[0]
|
||||||
|
`v`[`b`] = tmp[1]
|
||||||
|
elif swizzle.len == 3:
|
||||||
|
let
|
||||||
|
a = num(swizzle[0], fields)
|
||||||
|
b = num(swizzle[1], fields)
|
||||||
|
c = num(swizzle[2], fields)
|
||||||
|
result = quote do:
|
||||||
|
block:
|
||||||
|
let tmp = `e`
|
||||||
|
`v`[`a`] = tmp[0]
|
||||||
|
`v`[`b`] = tmp[1]
|
||||||
|
`v`[`c`] = tmp[2]
|
||||||
|
elif swizzle.len == 4:
|
||||||
|
let
|
||||||
|
a = num(swizzle[0], fields)
|
||||||
|
b = num(swizzle[1], fields)
|
||||||
|
c = num(swizzle[2], fields)
|
||||||
|
d = num(swizzle[3], fields)
|
||||||
|
result = quote do:
|
||||||
|
block:
|
||||||
|
let tmp = `e`
|
||||||
|
`v`[`a`] = tmp[0]
|
||||||
|
`v`[`b`] = tmp[1]
|
||||||
|
`v`[`c`] = tmp[2]
|
||||||
|
`v`[`d`] = tmp[3]
|
||||||
|
else:
|
||||||
|
error "invalid number of swizzle characters: " & swizzle, fields
|
||||||
|
|
||||||
proc `==`*[T](a, b: GVec2[T]): bool =
|
proc `==`*[T](a, b: GVec2[T]): bool =
|
||||||
a.x == b.x and a.y == b.y
|
a.x == b.x and a.y == b.y
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
## MIT License
|
## MIT License
|
||||||
## Copyright (c) 2021 Edin Omeragic
|
## Copyright (c) 2021 Edin Omeragic
|
||||||
|
|
||||||
import chroma, math, times, pixie, vmath, benchy
|
import benchy, chroma, math, pixie, times, vmath
|
||||||
|
|
||||||
{.push inline, noinit, checks: off.}
|
{.push inline, noinit, checks: off.}
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,6 @@ proc `[]=`(a: var Vec3ObjArr, i: int, v: float32) {.inline.} =
|
||||||
proc set(a: var Vec3Tuple, i: int, v: float32) {.inline.} =
|
proc set(a: var Vec3Tuple, i: int, v: float32) {.inline.} =
|
||||||
cast[ptr float32](cast[uint64](a.addr) + i.uint64 * sizeof(float32).uint64)[] = v
|
cast[ptr float32](cast[uint64](a.addr) + i.uint64 * sizeof(float32).uint64)[] = v
|
||||||
|
|
||||||
|
|
||||||
timeIt "vec3Obj[static]=", 1000:
|
timeIt "vec3Obj[static]=", 1000:
|
||||||
var v = vec3Obj(1, 2, 3)
|
var v = vec3Obj(1, 2, 3)
|
||||||
for i in 0 .. 1000000:
|
for i in 0 .. 1000000:
|
||||||
|
|
BIN
tests/raytracer.png
Normal file
BIN
tests/raytracer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 174 KiB |
|
@ -252,6 +252,15 @@ block:
|
||||||
_ = dvec3()
|
_ = dvec3()
|
||||||
_ = dvec4()
|
_ = dvec4()
|
||||||
|
|
||||||
|
var a = vec3(vec2(1, 2), 3)
|
||||||
|
doAssert a == vec3(1, 2, 3)
|
||||||
|
|
||||||
|
var b = vec4(vec3(1, 2, 3), 4)
|
||||||
|
doAssert b == vec4(1, 2, 3, 4)
|
||||||
|
|
||||||
|
var c = vec4(vec2(1, 2), vec2(3, 4))
|
||||||
|
doAssert c == vec4(1, 2, 3, 4)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
# test $ string functions
|
# test $ string functions
|
||||||
doAssert $bvec2(true, false) == "bvec2(true, false)"
|
doAssert $bvec2(true, false) == "bvec2(true, false)"
|
||||||
|
@ -278,6 +287,66 @@ block:
|
||||||
echo vec3(1.0, 2.0, 3.0)
|
echo vec3(1.0, 2.0, 3.0)
|
||||||
echo vec4(1.0, 2.0, 3.0, 4.0)
|
echo vec4(1.0, 2.0, 3.0, 4.0)
|
||||||
|
|
||||||
|
block:
|
||||||
|
# test swizzle vec
|
||||||
|
var a = vec2(1, 2)
|
||||||
|
doAssert a.x == 1.0
|
||||||
|
doAssert a.y == 2.0
|
||||||
|
doAssert a.yx == vec2(2, 1)
|
||||||
|
doAssert a.gr == vec2(2, 1)
|
||||||
|
doAssert a.ts == vec2(2, 1)
|
||||||
|
doAssert a.xxx == vec3(1, 1, 1)
|
||||||
|
|
||||||
|
a.yx = vec2(-1, -2)
|
||||||
|
doAssert a == vec2(-2, -1)
|
||||||
|
|
||||||
|
a.xx = vec2(-7, -3)
|
||||||
|
doAssert a == vec2(-3, -1)
|
||||||
|
|
||||||
|
when compiles(a.xyzxyz):
|
||||||
|
doAssert false
|
||||||
|
|
||||||
|
when compiles(a.z = 123):
|
||||||
|
doAssert false
|
||||||
|
|
||||||
|
var b = vec4(1, 2, 3, 4)
|
||||||
|
doAssert b == vec4(1, 2, 3, 4)
|
||||||
|
b.wzyx = b
|
||||||
|
doAssert b == vec4(4, 3, 2, 1)
|
||||||
|
|
||||||
|
b.g = 123
|
||||||
|
doAssert b == vec4(4.0, 123.0, 2.0, 1.0)
|
||||||
|
|
||||||
|
block:
|
||||||
|
# test swizzle dvec float64
|
||||||
|
var a = dvec2(1, 2)
|
||||||
|
doAssert a.x == 1.0
|
||||||
|
doAssert a.y == 2.0
|
||||||
|
doAssert a.yx == dvec2(2, 1)
|
||||||
|
doAssert a.gr == dvec2(2, 1)
|
||||||
|
doAssert a.ts == dvec2(2, 1)
|
||||||
|
doAssert a.xxx == dvec3(1, 1, 1)
|
||||||
|
|
||||||
|
a.yx = dvec2(-1, -2)
|
||||||
|
doAssert a == dvec2(-2, -1)
|
||||||
|
|
||||||
|
a.xx = dvec2(-7, -3)
|
||||||
|
doAssert a == dvec2(-3, -1)
|
||||||
|
|
||||||
|
when compiles(a.xyzxyz):
|
||||||
|
doAssert false
|
||||||
|
|
||||||
|
when compiles(a.z = 123):
|
||||||
|
doAssert false
|
||||||
|
|
||||||
|
var b = dvec4(1, 2, 3, 4)
|
||||||
|
doAssert b == dvec4(1, 2, 3, 4)
|
||||||
|
b.wzyx = b
|
||||||
|
doAssert b == dvec4(4, 3, 2, 1)
|
||||||
|
|
||||||
|
b.g = 123
|
||||||
|
doAssert b == dvec4(4.0, 123.0, 2.0, 1.0)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
# Test basic mat constructors.
|
# Test basic mat constructors.
|
||||||
block:
|
block:
|
||||||
|
|
Loading…
Reference in a new issue