v2 / vlib / gg / m4 / vector.v
250 lines · 226 sloc · 5.09 KB · f77bb32044c5130e9f0aeac26e72443a5fe9dc75
Raw
1/**********************************************************************
2* Simple vector/matrix utility
3* Copyright (c) 2024 Dario Deledda. All rights reserved.
4* Use of this source code is governed by an MIT license
5* that can be found in the LICENSE file.
6**********************************************************************/
7module m4
8
9import math
10
11pub struct Vec4 {
12pub mut:
13 e [4]f32
14}
15
16// str returns a `string` representation of `Vec4`.
17pub fn (x Vec4) str() string {
18 return '|${x.e[0]:-6.3},${x.e[1]:-6.3},${x.e[2]:-6.3},${x.e[3]:-6.3}|'
19}
20
21// vec3 creates a Vec4 value, passing x,y,z as parameters. The w element is set to 1
22@[inline]
23pub fn vec3(x f32, y f32, z f32) Vec4 {
24 return Vec4{
25 e: [x, y, z, 1]!
26 }
27}
28
29// vec4 creates a Vec4 value, based on the x,y,z,w parameters
30@[inline]
31pub fn vec4(x f32, y f32, z f32, w f32) Vec4 {
32 return Vec4{
33 e: [x, y, z, w]!
34 }
35}
36
37// is_equal checks if two vector are equal using the module precision (10e-7)
38@[direct_array_access]
39pub fn (x Vec4) is_equal(y Vec4) bool {
40 unsafe {
41 for c, value in x.e {
42 if f32_abs(value - y.e[c]) > precision {
43 return false
44 }
45 }
46 return true
47 }
48}
49
50// clean returns a new vector, based on `x`, but with all the values < precision, set to 0
51@[direct_array_access]
52pub fn (x Vec4) clean() Vec4 {
53 mut n := x
54 for c, value in x.e {
55 if f32_abs(value) < precision {
56 n.e[c] = 0
57 }
58 }
59 return n
60}
61
62// copy sets all elements of `x` to `value`
63pub fn (mut x Vec4) copy(value f32) {
64 x.e = [value, value, value, value]!
65}
66
67// mul_scalar returns the result of multiplying the vector `x`, by the scalar `value`
68@[inline]
69pub fn (x Vec4) mul_scalar(value f32) Vec4 {
70 return Vec4{
71 e: [x.e[0] * value, x.e[1] * value, x.e[2] * value, x.e[3] * value]!
72 }
73}
74
75// inv returns the reciprocal of the vector `x`
76pub fn (x Vec4) inv() Vec4 {
77 return Vec4{
78 e: [
79 if x.e[0] != 0 { 1.0 / x.e[0] } else { 0 },
80 if x.e[1] != 0 { 1.0 / x.e[1] } else { 0 },
81 if x.e[2] != 0 { 1.0 / x.e[2] } else { 0 },
82 if x.e[3] != 0 { 1.0 / x.e[3] } else { 0 },
83 ]!
84 }
85}
86
87// normalize returns a normalized form of the vector `x`
88pub fn (x Vec4) normalize() Vec4 {
89 m := x.mod()
90 if m == 0 {
91 return zero_v4()
92 }
93 return Vec4{
94 e: [
95 x.e[0] * (1 / m),
96 x.e[1] * (1 / m),
97 x.e[2] * (1 / m),
98 x.e[3] * (1 / m),
99 ]!
100 }
101}
102
103// normalize3 returns a normalized form of the vector `x`, where the w element is set to 0
104pub fn (x Vec4) normalize3() Vec4 {
105 m := x.mod3()
106 if m == 0 {
107 return zero_v4()
108 }
109 return Vec4{
110 e: [
111 x.e[0] * (1 / m),
112 x.e[1] * (1 / m),
113 x.e[2] * (1 / m),
114 0,
115 ]!
116 }
117}
118
119// mod returns a module of the vector `x`
120@[inline]
121pub fn (x Vec4) mod() f32 {
122 return math.sqrtf(x.e[0] * x.e[0] + x.e[1] * x.e[1] + x.e[2] * x.e[2] + x.e[3] * x.e[3])
123}
124
125// mod3 returns a module of the 3d vector `x`, ignoring the value of its w element
126@[inline]
127pub fn (x Vec4) mod3() f32 {
128 return math.sqrtf(x.e[0] * x.e[0] + x.e[1] * x.e[1] + x.e[2] * x.e[2])
129}
130
131/*********************************************************************
132* Math
133*********************************************************************/
134// zero_v4 returns a zero vector (all elements set to 0)
135@[inline]
136pub fn zero_v4() Vec4 {
137 return Vec4{
138 e: [
139 f32(0),
140 0,
141 0,
142 0,
143 ]!
144 }
145}
146
147// one_v4 returns a vector, where all elements are set to 1
148@[inline]
149pub fn one_v4() Vec4 {
150 return Vec4{
151 e: [
152 f32(1),
153 1,
154 1,
155 1,
156 ]!
157 }
158}
159
160// blank_v4 returns a vector, where all elements are set to 0, except `w`, which is set to 1
161pub fn blank_v4() Vec4 {
162 return Vec4{
163 e: [
164 f32(0),
165 0,
166 0,
167 1,
168 ]!
169 }
170}
171
172// set_v4 returns a vector, where all elements are set to `value`
173@[inline]
174pub fn set_v4(value f32) Vec4 {
175 return Vec4{
176 e: [
177 value,
178 value,
179 value,
180 value,
181 ]!
182 }
183}
184
185// sum returns a sum of all the elements
186@[inline]
187pub fn (x Vec4) sum() f32 {
188 return x.e[0] + x.e[1] + x.e[2] + x.e[3]
189}
190
191/*********************************************************************
192* Operators
193*********************************************************************/
194// + returns `a` + `b` (corresponding elements are added)
195@[inline]
196pub fn (a Vec4) + (b Vec4) Vec4 {
197 return Vec4{
198 e: [
199 a.e[0] + b.e[0],
200 a.e[1] + b.e[1],
201 a.e[2] + b.e[2],
202 a.e[3] + b.e[3],
203 ]!
204 }
205}
206
207// - returns `a` + `b` (corresponding elements are subtracted)
208@[inline]
209pub fn (a Vec4) - (b Vec4) Vec4 {
210 return Vec4{
211 e: [
212 a.e[0] - b.e[0],
213 a.e[1] - b.e[1],
214 a.e[2] - b.e[2],
215 a.e[3] - b.e[3],
216 ]!
217 }
218}
219
220// * returns `a` * `b` (corresponding elements are multiplied, then summed), i.e. a dot product
221@[inline]
222pub fn (a Vec4) * (b Vec4) f32 {
223 return a.e[0] * b.e[0] + a.e[1] * b.e[1] + a.e[2] * b.e[2] + a.e[3] * b.e[3]
224}
225
226// % returns a cross product of the vectors `a` and `b`
227@[inline]
228pub fn (a Vec4) % (b Vec4) Vec4 {
229 return Vec4{
230 e: [
231 (a.e[1] * b.e[2]) - (a.e[2] * b.e[1]),
232 (a.e[2] * b.e[0]) - (a.e[0] * b.e[2]),
233 (a.e[0] * b.e[1]) - (a.e[1] * b.e[0]),
234 0,
235 ]!
236 }
237}
238
239// mul_vec4 returns a vector, where the corresponding `x` and `y` elements are multiplied
240@[inline]
241pub fn (x Vec4) mul_vec4(y Vec4) Vec4 {
242 return Vec4{
243 e: [
244 x.e[0] * y.e[0],
245 x.e[1] * y.e[1],
246 x.e[2] * y.e[2],
247 x.e[3] * y.e[3],
248 ]!
249 }
250}
251