478
|
1 import std/random
|
|
2 import std/math
|
|
3 import std/strutils
|
|
4 import std/macros
|
|
5 import std/typetraits
|
|
6 import std/tables
|
|
7
|
|
8
|
|
9 type
|
|
10 Vec2*[T: SomeNumber] = array[2, T]
|
|
11 Vec3*[T: SomeNumber] = array[3, T]
|
|
12 Vec4*[T: SomeNumber] = array[4, T]
|
|
13 Vec* = Vec2|Vec3|Vec4
|
|
14
|
|
15 # define some often used constants
|
|
16 func ConstOne2[T: SomeNumber](): auto {.compiletime.} = Vec2[T]([T(1), T(1)])
|
|
17 func ConstOne3[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(1), T(1), T(1)])
|
|
18 func ConstOne4[T: SomeNumber](): auto {.compiletime.} = Vec4[T]([T(1), T(1), T(1), T(1)])
|
|
19 func ConstX[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(1), T(0), T(0)])
|
|
20 func ConstY[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(0), T(1), T(0)])
|
|
21 func ConstZ[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(0), T(0), T(1)])
|
|
22 func ConstR[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(1), T(0), T(0)])
|
|
23 func ConstG[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(0), T(1), T(0)])
|
|
24 func ConstB[T: SomeNumber](): auto {.compiletime.} = Vec3[T]([T(0), T(0), T(1)])
|
|
25
|
|
26 # generates constants: Xf, Xf32, Xf64, Xi, Xi8, Xi16, Xi32, Xi64
|
|
27 # Also for Y, Z, R, G, B and One
|
|
28 # not sure if this is necessary or even a good idea...
|
|
29 macro generateAllConsts() =
|
|
30 result = newStmtList()
|
|
31 for component in ["X", "Y", "Z", "R", "G", "B", "One2", "One3", "One4"]:
|
|
32 for theType in ["int", "int8", "int16", "int32", "int64", "float", "float32", "float64"]:
|
|
33 var typename = theType[0 .. 0]
|
|
34 if theType[^2].isDigit:
|
|
35 typename = typename & theType[^2]
|
|
36 if theType[^1].isDigit:
|
|
37 typename = typename & theType[^1]
|
|
38 result.add(
|
|
39 newConstStmt(
|
|
40 postfix(ident(component & typename), "*"),
|
|
41 newCall(nnkBracketExpr.newTree(ident("Const" & component), ident(theType)))
|
|
42 )
|
|
43 )
|
|
44
|
|
45 generateAllConsts()
|
|
46
|
|
47 const X* = ConstX[float]()
|
|
48 const Y* = ConstY[float]()
|
|
49 const Z* = ConstZ[float]()
|
|
50 const One2* = ConstOne2[float]()
|
|
51 const One3* = ConstOne3[float]()
|
|
52 const One4* = ConstOne4[float]()
|
|
53
|
|
54 func newVec2*[T](x, y: T): auto = Vec2([x, y])
|
|
55 func newVec3*[T](x, y, z: T): auto = Vec3([x, y, z])
|
|
56 func newVec4*[T](x, y, z, w: T): auto = Vec4([x, y, z, w])
|
|
57
|
|
58 func to*[T](v: Vec2): auto = Vec2([T(v[0]), T(v[1])])
|
|
59 func to*[T](v: Vec3): auto = Vec3([T(v[0]), T(v[1]), T(v[2])])
|
|
60 func to*[T](v: Vec4): auto = Vec4([T(v[0]), T(v[1]), T(v[2]), T(v[3])])
|
|
61
|
|
62 func toString[T](value: T): string =
|
|
63 var items: seq[string]
|
|
64 for item in value:
|
|
65 items.add($item)
|
|
66 $T & "(" & join(items, " ") & ")"
|
|
67
|
|
68 func `$`*(v: Vec2[SomeNumber]): string = toString[Vec2[SomeNumber]](v)
|
|
69 func `$`*(v: Vec3[SomeNumber]): string = toString[Vec3[SomeNumber]](v)
|
|
70 func `$`*(v: Vec4[SomeNumber]): string = toString[Vec4[SomeNumber]](v)
|
|
71
|
|
72 func length*(vec: Vec2[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1])
|
|
73 func length*(vec: Vec2[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1]))
|
|
74 func length*(vec: Vec3[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2])
|
|
75 func length*(vec: Vec3[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]))
|
|
76 func length*(vec: Vec4[SomeFloat]): auto = sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3])
|
|
77 func length*(vec: Vec4[SomeInteger]): auto = sqrt(float(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2] + vec[3] * vec[3]))
|
|
78
|
|
79 func normalized*[T](vec: Vec2[T]): auto =
|
|
80 let l = vec.length
|
|
81 when T is SomeFloat:
|
|
82 Vec2[T]([vec[0] / l, vec[1] / l])
|
|
83 else:
|
|
84 Vec2[float]([float(vec[0]) / l, float(vec[1]) / l])
|
|
85 func normalized*[T](vec: Vec3[T]): auto =
|
|
86 let l = vec.length
|
|
87 when T is SomeFloat:
|
|
88 Vec3[T]([vec[0] / l, vec[1] / l, vec[2] / l])
|
|
89 else:
|
|
90 Vec3[float]([float(vec[0]) / l, float(vec[1]) / l, float(vec[2]) / l])
|
|
91 func normalized*[T](vec: Vec4[T]): auto =
|
|
92 let l = vec.length
|
|
93 when T is SomeFloat:
|
|
94 Vec4[T]([vec[0] / l, vec[1] / l, vec[2] / l, vec[3] / l])
|
|
95 else:
|
|
96 Vec4[float]([float(vec[0]) / l, float(vec[1]) / l, float(vec[2]) / l, float(vec[3]) / l])
|
|
97
|
|
98 # scalar operations
|
|
99 func `+`*(a: Vec2, b: SomeNumber): auto = Vec2([a[0] + b, a[1] + b])
|
|
100 func `+`*(a: Vec3, b: SomeNumber): auto = Vec3([a[0] + b, a[1] + b, a[2] + b])
|
|
101 func `+`*(a: Vec4, b: SomeNumber): auto = Vec4([a[0] + b, a[1] + b, a[2] + b, a[3] + b])
|
|
102 func `-`*(a: Vec2, b: SomeNumber): auto = Vec2([a[0] - b, a[1] - b])
|
|
103 func `-`*(a: Vec3, b: SomeNumber): auto = Vec3([a[0] - b, a[1] - b, a[2] - b])
|
|
104 func `-`*(a: Vec4, b: SomeNumber): auto = Vec4([a[0] - b, a[1] - b, a[2] - b, a[3] - b])
|
|
105 func `*`*(a: Vec2, b: SomeNumber): auto = Vec2([a[0] * b, a[1] * b])
|
|
106 func `*`*(a: Vec3, b: SomeNumber): auto = Vec3([a[0] * b, a[1] * b, a[2] * b])
|
|
107 func `*`*(a: Vec4, b: SomeNumber): auto = Vec4([a[0] * b, a[1] * b, a[2] * b, a[3] * b])
|
|
108 func `/`*[T: SomeInteger](a: Vec2[T], b: SomeInteger): auto = Vec2([a[0] div b, a[1] div b])
|
|
109 func `/`*[T: SomeFloat](a: Vec2[T], b: SomeFloat): auto = Vec2([a[0] / b, a[1] / b])
|
|
110 func `/`*[T: SomeInteger](a: Vec3[T], b: SomeInteger): auto = Vec3([a[0] div b, a[1] div b, a[2] div b])
|
|
111 func `/`*[T: SomeFloat](a: Vec3[T], b: SomeFloat): auto = Vec3([a[0] / b, a[1] / b, a[2] / b])
|
|
112 func `/`*[T: SomeInteger](a: Vec4[T], b: SomeInteger): auto = Vec4([a[0] div b, a[1] div b, a[2] div b, a[3] div b])
|
|
113 func `/`*[T: SomeFloat](a: Vec4[T], b: SomeFloat): auto = Vec4([a[0] / b, a[1] / b, a[2] / b, a[3] / b])
|
|
114
|
|
115 func `+`*(a: SomeNumber, b: Vec2): auto = Vec2([a + b[0], a + b[1]])
|
|
116 func `+`*(a: SomeNumber, b: Vec3): auto = Vec3([a + b[0], a + b[1], a + b[2]])
|
|
117 func `+`*(a: SomeNumber, b: Vec4): auto = Vec4([a + b[0], a + b[1], a + b[2], a + b[3]])
|
|
118 func `-`*(a: SomeNumber, b: Vec2): auto = Vec2([a - b[0], a - b[1]])
|
|
119 func `-`*(a: SomeNumber, b: Vec3): auto = Vec3([a - b[0], a - b[1], a - b[2]])
|
|
120 func `-`*(a: SomeNumber, b: Vec4): auto = Vec4([a - b[0], a - b[1], a - b[2], a - b[3]])
|
|
121 func `*`*(a: SomeNumber, b: Vec2): auto = Vec2([a * b[0], a * b[1]])
|
|
122 func `*`*(a: SomeNumber, b: Vec3): auto = Vec3([a * b[0], a * b[1], a * b[2]])
|
|
123 func `*`*(a: SomeNumber, b: Vec4): auto = Vec4([a * b[0], a * b[1], a * b[2], a * b[3]])
|
|
124 func `/`*[T: SomeInteger](a: SomeInteger, b: Vec2[T]): auto = Vec2([a div b[0], a div b[1]])
|
|
125 func `/`*[T: SomeFloat](a: SomeFloat, b: Vec2[T]): auto = Vec2([a / b[0], a / b[1]])
|
|
126 func `/`*[T: SomeInteger](a: SomeInteger, b: Vec3[T]): auto = Vec3([a div b[0], a div b[1], a div b[2]])
|
|
127 func `/`*[T: SomeFloat](a: SomeFloat, b: Vec3[T]): auto = Vec3([a / b[0], a / b[1], a / b[2]])
|
|
128 func `/`*[T: SomeInteger](a: SomeInteger, b: Vec4[T]): auto = Vec4([a div b[0], a div b[1], a div b[2], a div b[3]])
|
|
129 func `/`*[T: SomeFloat](a: SomeFloat, b: Vec4[T]): auto = Vec4([a / b[0], a / b[1], a / b[2], a / b[3]])
|
|
130
|
|
131 # compontent-wise operations
|
|
132 func `+`*(a, b: Vec2): auto = Vec2([a[0] + b[0], a[1] + b[1]])
|
|
133 func `+`*(a, b: Vec3): auto = Vec3([a[0] + b[0], a[1] + b[1], a[2] + b[2]])
|
|
134 func `+`*(a, b: Vec4): auto = Vec4([a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]])
|
|
135 func `-`*(a: Vec2): auto = Vec2([-a[0], -a[1]])
|
|
136 func `-`*(a: Vec3): auto = Vec3([-a[0], -a[1], -a[2]])
|
|
137 func `-`*(a: Vec4): auto = Vec4([-a[0], -a[1], -a[2], -a[3]])
|
|
138 func `-`*(a, b: Vec2): auto = Vec2([a[0] - b[0], a[1] - b[1]])
|
|
139 func `-`*(a, b: Vec3): auto = Vec3([a[0] - b[0], a[1] - b[1], a[2] - b[2]])
|
|
140 func `-`*(a, b: Vec4): auto = Vec4([a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]])
|
|
141 func `*`*(a, b: Vec2): auto = Vec2([a[0] * b[0], a[1] * b[1]])
|
|
142 func `*`*(a, b: Vec3): auto = Vec3([a[0] * b[0], a[1] * b[1], a[2] * b[2]])
|
|
143 func `*`*(a, b: Vec4): auto = Vec4([a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]])
|
|
144 func `/`*[T: SomeInteger](a, b: Vec2[T]): auto = Vec2([a[0] div b[0], a[1] div b[1]])
|
|
145 func `/`*[T: SomeFloat](a, b: Vec2[T]): auto = Vec2([a[0] / b[0], a[1] / b[1]])
|
|
146 func `/`*[T: SomeInteger](a, b: Vec3[T]): auto = Vec3([a[0] div b[0], a[1] div b[1], a[2] div b[2]])
|
|
147 func `/`*[T: SomeFloat](a, b: Vec3[T]): auto = Vec3([a[0] / b[0], a[1] / b[1], a[2] / b[2]])
|
|
148 func `/`*[T: SomeInteger](a, b: Vec4[T]): auto = Vec4([a[0] div b[0], a[1] div b[1], a[2] div b[2], a[3] div b[3]])
|
|
149 func `/`*[T: SomeFloat](a, b: Vec4[T]): auto = Vec4([a[0] / b[0], a[1] / b[1], a[2] / b[2], a[3] / b[3]])
|
|
150
|
|
151 # special operations
|
|
152 func dot*(a, b: Vec2): auto = a[0] * b[0] + a[1] * b[1]
|
|
153 func dot*(a, b: Vec3): auto = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
|
|
154 func dot*(a, b: Vec4): auto = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
|
|
155 func cross*(a, b: Vec3): auto = Vec3([
|
|
156 a[1] * b[2] - a[2] * b[1],
|
|
157 a[2] * b[0] - a[0] * b[2],
|
|
158 a[0] * b[1] - a[1] * b[0],
|
|
159 ])
|
|
160
|
|
161
|
|
162 # macro to allow creation of new vectors by specifying vector components as attributes
|
|
163 # e.g. myVec.xxy will return a new Vec3 that contains the components x, x an y of the original vector
|
|
164 # (instead of x, y, z for a simple copy)
|
|
165 proc vectorAttributeAccessor(accessor: string): NimNode =
|
|
166 const ACCESSOR_INDICES = {
|
|
167 'x': 0,
|
|
168 'y': 1,
|
|
169 'z': 2,
|
|
170 'w': 3,
|
|
171 'r': 0,
|
|
172 'g': 1,
|
|
173 'b': 2,
|
|
174 'a': 3,
|
|
175 }.toTable
|
|
176 var ret: NimNode
|
|
177 let accessorvalue = accessor
|
|
178
|
|
179 if accessorvalue.len == 0:
|
|
180 raise newException(Exception, "empty attribute")
|
|
181 elif accessorvalue.len == 1:
|
|
182 ret = nnkBracket.newTree(ident("value"), newLit(ACCESSOR_INDICES[accessorvalue[0]]))
|
|
183 if accessorvalue.len > 1:
|
|
184 var attrs = nnkBracket.newTree()
|
|
185 for attrname in accessorvalue:
|
|
186 attrs.add(nnkBracketExpr.newTree(ident("value"), newLit(ACCESSOR_INDICES[attrname])))
|
|
187 ret = nnkCall.newTree(ident("Vec" & $accessorvalue.len), attrs)
|
|
188
|
|
189 newProc(
|
|
190 name=nnkPostfix.newTree(ident("*"), ident(accessor)),
|
|
191 params=[ident("auto"), nnkIdentDefs.newTree(ident("value"), ident("Vec"), newEmptyNode())],
|
|
192 body=newStmtList(ret),
|
|
193 procType = nnkFuncDef,
|
|
194 )
|
|
195
|
|
196 macro createVectorAttribAccessorFuncs() =
|
|
197 const COORD_ATTRS = ["x", "y", "z", "w"]
|
|
198 const COLOR_ATTRS = ["r", "g", "b", "a"]
|
|
199 result = nnkStmtList.newTree()
|
|
200 for attlist in [COORD_ATTRS, COLOR_ATTRS]:
|
|
201 for i in attlist:
|
|
202 result.add(vectorAttributeAccessor(i))
|
|
203 for j in attlist:
|
|
204 result.add(vectorAttributeAccessor(i & j))
|
|
205 for k in attlist:
|
|
206 result.add(vectorAttributeAccessor(i & j & k))
|
|
207 for l in attlist:
|
|
208 result.add(vectorAttributeAccessor(i & j & k & l))
|
|
209
|
|
210 createVectorAttribAccessorFuncs()
|
|
211
|
|
212 # call e.g. Vec2[int]().randomized() to get a random matrix
|
|
213 template makeRandomInit(mattype: typedesc) =
|
|
214 proc randomized*[T: SomeInteger](m: mattype[T]): mattype[T] =
|
|
215 for i in 0 ..< result.len:
|
|
216 result[i] = rand(low(typeof(m[0])) .. high(typeof(m[0])))
|
|
217 proc randomized*[T: SomeFloat](m: mattype[T]): mattype[T] =
|
|
218 for i in 0 ..< result.len:
|
|
219 result[i] = rand(1.0)
|
|
220
|
|
221 makeRandomInit(Vec2)
|
|
222 makeRandomInit(Vec3)
|
|
223 makeRandomInit(Vec4)
|