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