VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
vector3.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Created by Arnis Lektauers on 18.07.2025.
5//
6
7#pragma once
8
9#include <iostream>
10
11#include "defines.h"
12
13namespace visutwin::canvas
14{
15 struct Matrix4;
16 struct Vector4;
17
18 typedef std::array<float, 3> PackedVector3f;
19
28 struct alignas(16) Vector3
29 {
30 union
31 {
32#if defined(USE_SIMD_SSE)
33 __m128 m128;
34#elif defined(USE_SIMD_APPLE)
35 simd_float3 m128;
36#elif defined(USE_SIMD_NEON)
37 float32x4_t m128;
38#else
39 struct
40 {
41 float x, y, z;
42 };
43 float v[3];
44#endif
45 };
46
50
52 {
53#if defined(USE_SIMD_SSE)
54 m128 = _mm_setzero_ps();
55#elif defined(USE_SIMD_APPLE)
56 m128 = simd_make_float3(0.0f, 0.0f, 0.0f);
57#elif defined(USE_SIMD_NEON)
58 m128 = vdupq_n_f32(0.0f);
59#else
60 x = y = z = 0.0f;
61#endif
62 }
63
64 explicit Vector3(const float s)
65 {
66#if defined(USE_SIMD_SSE)
67 m128 = _mm_set_ps(0.0f, s, s, s); // w must be 0 for 3-component dot/length
68#elif defined(USE_SIMD_APPLE)
69 m128 = simd_make_float3(s, s, s);
70#elif defined(USE_SIMD_NEON)
71 m128 = vsetq_lane_f32(0.0f, vdupq_n_f32(s), 3); // w must be 0 for 3-component dot/length
72#else
73 x = y = z = s;
74#endif
75 }
76
77 Vector3(const float x, const float y, const float z)
78 {
79#if defined(USE_SIMD_SSE)
80 m128 = _mm_set_ps(0.0f, z, y, x); // last = x, then y, then z, then 0
81#elif defined(USE_SIMD_APPLE)
82 m128 = simd_make_float3(x, y, z);
83#elif defined(USE_SIMD_NEON)
84 float temp[4] = { x, y, z, 0.0f };
85 m128 = vld1q_f32(temp);
86#else
87 v[0] = x;
88 v[1] = y;
89 v[2] = z;
90#endif
91 }
92
93 Vector3(const Vector4& other);
94
95#if defined(USE_SIMD_SSE)
96 explicit Vector3(const __m128& data) : m128(data) {}
97#elif defined(USE_SIMD_NEON)
98 explicit Vector3(const float32x4_t& data) : m128(data) {}
99#endif
100
101#if defined(USE_SIMD_APPLE)
102 explicit Vector3(const simd_float4& data) : m128(simd_make_float3(data)) {}
103
104 explicit Vector3(const simd_float3& data) : m128(data) {}
105#endif
106
107 explicit Vector3(const PackedVector3f& packed) {
108#if defined(USE_SIMD_SSE)
109 m128 = _mm_set_ps(0.0f, packed[2], packed[1], packed[0]); // w, z, y, x (reverse order)
110#elif defined(USE_SIMD_APPLE)
111 m128 = simd_make_float3(packed[0], packed[1], packed[2]);
112#elif defined(USE_SIMD_NEON)
113 float temp[4] = { packed[0], packed[1], packed[2], 0.0f };
114 m128 = vld1q_f32(temp);
115#else
116 x = packed[0];
117 y = packed[1];
118 z = packed[2];
119#endif
120 }
121
122 [[nodiscard]] float getX() const {
123#if defined(USE_SIMD_SSE)
124 return _mm_cvtss_f32(m128); // extracts the lowest float from __m128
125#elif defined(USE_SIMD_APPLE)
126 return m128.x;
127#elif defined(USE_SIMD_NEON)
128 return vgetq_lane_f32(m128, 0); // extract lane 0
129#else
130 return x; // fallback scalar path
131#endif
132 }
133
134 [[nodiscard]] float getY() const {
135#if defined(USE_SIMD_SSE)
136 return _mm_cvtss_f32(_mm_shuffle_ps(m128, m128, _MM_SHUFFLE(1,1,1,1)));
137#elif defined(USE_SIMD_APPLE)
138 return m128.y;
139#elif defined(USE_SIMD_NEON)
140 return vgetq_lane_f32(m128, 1);
141#else
142 return y;
143#endif
144 }
145
146 [[nodiscard]] float getZ() const {
147#if defined(USE_SIMD_SSE)
148 return _mm_cvtss_f32(_mm_shuffle_ps(m128, m128, _MM_SHUFFLE(2,2,2,2)));
149#elif defined(USE_SIMD_APPLE)
150 return m128.z;
151#elif defined(USE_SIMD_NEON)
152 return vgetq_lane_f32(m128, 2);
153#else
154 return z;
155#endif
156 }
157
158 Vector3 operator+(const Vector3& other) const
159 {
160#if defined(USE_SIMD_SSE)
161 return Vector3(_mm_add_ps(this->m128, other.m128));
162#elif defined(USE_SIMD_APPLE)
163 return Vector3(this->m128 + other.m128);
164#elif defined(USE_SIMD_NEON)
165 return Vector3(vaddq_f32(this->m128, other.m128));
166#else
167 return Vector3(this->x + other.x, this->y + other.y, this->z + other.z);
168#endif
169 }
170
172 {
173#if defined(USE_SIMD_SSE)
174 m128 = _mm_add_ps(m128, rhs.m128);
175#elif defined(USE_SIMD_APPLE)
176 m128 = m128 + rhs.m128;
177#elif defined(USE_SIMD_NEON)
178 m128 = vaddq_f32(m128, rhs.m128);
179#else
180 x += rhs.x;
181 y += rhs.y;
182 z += rhs.z;
183#endif
184 return *this;
185 }
186
187 Vector3 operator-(const Vector3& other) const
188 {
189#if defined(USE_SIMD_SSE)
190 return Vector3(_mm_sub_ps(this->m128, other.m128));
191#elif defined(USE_SIMD_APPLE)
192 return Vector3(this->m128 - other.m128);
193#elif defined(USE_SIMD_NEON)
194 return Vector3(vsubq_f32(this->m128, other.m128));
195#else
196 return Vector3(this->x - other.x, this->y - other.y, this->z - other.z);
197#endif
198 }
199
201 {
202#if defined(USE_SIMD_SSE)
203 m128 = _mm_sub_ps(m128, rhs.m128);
204#elif defined(USE_SIMD_APPLE)
205 m128 = m128 - rhs.m128;
206#elif defined(USE_SIMD_NEON)
207 m128 = vsubq_f32(m128, rhs.m128);
208#else
209 x -= rhs.x;
210 y -= rhs.y;
211 z -= rhs.z;
212#endif
213 return *this;
214 }
215
216 Vector3 operator*(float scalar) const;
217
218 Vector3 operator*(const Vector3& other) const;
219
220 [[nodiscard]] float dot(const Vector3& other) const;
221
222 [[nodiscard]] Vector3 normalized() const;
223
224 [[nodiscard]] float length() const
225 {
226#if defined(USE_SIMD_APPLE)
227 return simd_length(m128);
228#else
229 return std::sqrt(dot(*this));
230#endif
231 }
232
233 [[nodiscard]] float lengthSquared() const
234 {
235#if defined(USE_SIMD_APPLE)
236 return simd_length_squared(m128);
237#else
238 return dot(*this);
239#endif
240 }
241
242 [[nodiscard]] float distance(const Vector3& other) const
243 {
244#if defined(USE_SIMD_APPLE)
245 return simd_distance(m128, other.m128);
246#else
247 return (*this - other).length();
248#endif
249 }
250
251 [[nodiscard]] Vector3 cross(const Vector3& other) const;
252
253 void print() const
254 {
255#if defined(USE_SIMD_APPLE)
256 std::cout << "Vector3(" << m128.x << ", " << m128.y << ", " << m128.z << ")\n";
257#elif defined(USE_SIMD_SSE) || defined(USE_SIMD_NEON)
258 std::cout << "Vector3(" << getX() << ", " << getY() << ", " << getZ() << ")\n";
259#else
260 std::cout << "Vector3(" << x << ", " << y << ", " << z << ")\n";
261#endif
262 }
263
264 /*
265 * Constructs a 4×4 scaling matrix from a 3D scaling vector
266 */
267 [[nodiscard]] Matrix4 toScalingMatrix() const;
268
269 /*
270 * Creates a 4×4 transformation matrix that represents a translation using the given 3D offset vector
271 */
272 [[nodiscard]] Matrix4 toTranslationMatrix() const;
273
274 /*
275 * Transforms the given 3D vector by a 4×4 transformation matrix. It applies translation, rotation, and scaling.
276 */
277 [[nodiscard]] Vector3 transform(const Matrix4& mat) const;
278
279 /*
280 * Transforms the given 3D direction vector by a 4×4 transformation matrix, ignoring translation.
281 */
282 [[nodiscard]] Vector3 transformNormal(const Matrix4& mat) const;
283
285 };
286
287 template<typename T>
288 struct Vector3T
289 {
290 T x, y, z;
291
292 Vector3T() : x(0), y(0), z(0)
293 {
294 }
295
296 explicit Vector3T(const T s) : x(s), y(s), z(s)
297 {
298 }
299
300 Vector3T(const T x, const T y, const T z) : x(x), y(y), z(z)
301 {
302 }
303
304 Vector3T<T> operator-(const Vector3T& other) const
305 {
306 return Vector3T<T>(x - other.x, y - other.y, z - other.z);
307 }
308
309 [[nodiscard]] float length() const
310 {
311 return std::sqrt(x * x + y * y + z * z);
312 }
313 };
314
316}
317
318#include "vector3.inl"
Vector3T< int > Vector3i
Definition vector3.h:315
std::array< float, 3 > PackedVector3f
Definition vector3.h:18
4x4 column-major transformation matrix with SIMD acceleration.
Definition matrix4.h:31
Vector3 cross(const Vector3 &other) const
Matrix4 toScalingMatrix() const
static Vector3 UNIT_Z
Definition vector3.h:49
Vector3(const float x, const float y, const float z)
Definition vector3.h:77
Vector3 & operator+=(const Vector3 &rhs)
Definition vector3.h:171
Vector3 normalized() const
Matrix4 toTranslationMatrix() const
static Vector3 UNIT_X
Definition vector3.h:47
Vector3 operator+(const Vector3 &other) const
Definition vector3.h:158
float distance(const Vector3 &other) const
Definition vector3.h:242
Vector3 operator-() const
Vector3(const Vector4 &other)
Vector3 & operator-=(const Vector3 &rhs)
Definition vector3.h:200
Vector3 transformNormal(const Matrix4 &mat) const
Vector3 operator-(const Vector3 &other) const
Definition vector3.h:187
float dot(const Vector3 &other) const
Vector3 transform(const Matrix4 &mat) const
Vector3(const PackedVector3f &packed)
Definition vector3.h:107
Vector3 operator*(const Vector3 &other) const
Vector3(const float s)
Definition vector3.h:64
float lengthSquared() const
Definition vector3.h:233
float length() const
Definition vector3.h:224
static Vector3 UNIT_Y
Definition vector3.h:48
Vector3 operator*(float scalar) const
Vector3T(const T x, const T y, const T z)
Definition vector3.h:300
Vector3T< T > operator-(const Vector3T &other) const
Definition vector3.h:304
4D vector for homogeneous coordinates, color values, and SIMD operations.
Definition vector4.h:20