1 #pragma once
2
3 /* greebo: This file contains the templated class definition of the three-component vector
4 *
5 * BasicVector4: A vector with three components of type <Element>
6 *
7 * The BasicVector4 is equipped with the most important operators like *, *= and so on.
8 *
9 * Note: The most commonly used Vector4 is a BasicVector4<float>, this is also defined in this file
10 *
11 * Note: that the multiplication of a Vector4 with another one (Vector4*Vector4) does NOT
12 * result in an inner product but in a component-wise scaling. Use the .dot() method to
13 * execute an inner product of two vectors.
14 */
15
16 #include "FloatTools.h"
17 #include "Vector3.h"
18
19 // A 4-element vector of type <Element>
20 template<typename Element>
21 class BasicVector4
22 {
23
24 // The components of this vector
25 Element m_elements[4];
26
27 public:
28
29 // Constructor (no arguments)
BasicVector4()30 BasicVector4 ()
31 {
32 }
33
34 // Construct a BasicVector4 out of the 4 arguments
BasicVector4(Element x_,Element y_,Element z_,Element w_)35 BasicVector4 (Element x_, Element y_, Element z_, Element w_)
36 {
37 x() = x_;
38 y() = y_;
39 z() = z_;
40 w() = w_;
41 }
42
43 // Construct a BasicVector4 out of a Vector3 plus a fourth argument
BasicVector4(const BasicVector3<Element> & self,Element w_)44 BasicVector4 (const BasicVector3<Element>& self, Element w_)
45 {
46 x() = self.x();
47 y() = self.y();
48 z() = self.z();
49 w() = w_;
50 }
51
52 /** Set all 4 components to the provided values.
53 */
set(const Element & x,const Element & y,const Element & z,const Element & a)54 void set (const Element& x, const Element& y, const Element& z, const Element& a)
55 {
56 m_elements[0] = x;
57 m_elements[1] = y;
58 m_elements[2] = z;
59 m_elements[3] = a;
60 }
61
62 // Return non-constant references to the components
x()63 Element& x ()
64 {
65 return m_elements[0];
66 }
y()67 Element& y ()
68 {
69 return m_elements[1];
70 }
z()71 Element& z ()
72 {
73 return m_elements[2];
74 }
w()75 Element& w ()
76 {
77 return m_elements[3];
78 }
79
80 // Return constant references to the components
x()81 const Element& x () const
82 {
83 return m_elements[0];
84 }
y()85 const Element& y () const
86 {
87 return m_elements[1];
88 }
z()89 const Element& z () const
90 {
91 return m_elements[2];
92 }
w()93 const Element& w () const
94 {
95 return m_elements[3];
96 }
97
index(std::size_t i)98 Element index (std::size_t i) const
99 {
100 return m_elements[i];
101 }
index(std::size_t i)102 Element& index (std::size_t i)
103 {
104 return m_elements[i];
105 }
106
107 /** Compare this BasicVector4 against another for equality.
108 */
109 bool operator== (const BasicVector4& other) const
110 {
111 return (other.x() == x() && other.y() == y() && other.z() == z() && other.w() == w());
112 }
113
114 /** Compare this BasicVector4 against another for inequality.
115 */
116 bool operator!= (const BasicVector4& other) const
117 {
118 return !(*this == other);
119 }
120
121 /* Define the addition operators + and += with any other BasicVector4 of type OtherElement
122 * The vectors are added to each other element-wise
123 */
124 template<typename OtherElement>
125 BasicVector4<Element> operator+ (const BasicVector4<OtherElement>& other) const
126 {
127 return BasicVector4<Element> (m_elements[0] + static_cast<Element> (other.x()), m_elements[1]
128 + static_cast<Element> (other.y()), m_elements[2] + static_cast<Element> (other.z()), m_elements[3]
129 + static_cast<Element> (other.w()));
130 }
131
132 template<typename OtherElement>
133 void operator+= (const BasicVector4<OtherElement>& other)
134 {
135 m_elements[0] += static_cast<Element> (other.x());
136 m_elements[1] += static_cast<Element> (other.y());
137 m_elements[2] += static_cast<Element> (other.z());
138 m_elements[3] += static_cast<Element> (other.w());
139 }
140
141 /* Define the substraction operators - and -= with any other BasicVector4 of type OtherElement
142 * The vectors are substracted from each other element-wise
143 */
144 template<typename OtherElement>
145 BasicVector4<Element> operator- (const BasicVector4<OtherElement>& other) const
146 {
147 return BasicVector4<Element> (m_elements[0] - static_cast<Element> (other.x()), m_elements[1]
148 - static_cast<Element> (other.y()), m_elements[2] - static_cast<Element> (other.z()), m_elements[3]
149 - static_cast<Element> (other.w()));
150 }
151
152 template<typename OtherElement>
153 void operator-= (const BasicVector4<OtherElement>& other)
154 {
155 m_elements[0] -= static_cast<Element> (other.x());
156 m_elements[1] -= static_cast<Element> (other.y());
157 m_elements[2] -= static_cast<Element> (other.z());
158 m_elements[3] -= static_cast<Element> (other.w());
159 }
160
161 /* Define the multiplication operators * and *= with another Vector4 of type OtherElement
162 *
163 * The vectors are multiplied element-wise
164 *
165 * greebo: This is mathematically kind of senseless, as this is a mixture of
166 * a dot product and scalar multiplication. It can be used to scale each
167 * vector component by a different factor, so maybe this comes in handy.
168 */
169 template<typename OtherElement>
170 BasicVector4<Element> operator* (const BasicVector4<OtherElement>& other) const
171 {
172 return BasicVector4<Element> (m_elements[0] * static_cast<Element> (other.x()), m_elements[1]
173 * static_cast<Element> (other.y()), m_elements[2] * static_cast<Element> (other.z()), m_elements[3]
174 * static_cast<Element> (other.w()));
175 }
176
177 template<typename OtherElement>
178 void operator*= (const BasicVector4<OtherElement>& other)
179 {
180 m_elements[0] *= static_cast<Element> (other.x());
181 m_elements[1] *= static_cast<Element> (other.y());
182 m_elements[2] *= static_cast<Element> (other.z());
183 m_elements[3] *= static_cast<Element> (other.w());
184 }
185
186 /* Define the multiplications * and *= with a scalar
187 */
188 template<typename OtherElement>
189 BasicVector4<Element> operator* (const OtherElement& other) const
190 {
191 Element factor = static_cast<Element> (other);
192 return BasicVector4<Element> (m_elements[0] * factor, m_elements[1] * factor, m_elements[2] * factor,
193 m_elements[3] * factor);
194 }
195
196 template<typename OtherElement>
197 void operator*= (const OtherElement& other)
198 {
199 Element factor = static_cast<Element> (other);
200 m_elements[0] *= factor;
201 m_elements[1] *= factor;
202 m_elements[2] *= factor;
203 m_elements[3] *= factor;
204 }
205
206 /* Define the division operators / and /= with another Vector4 of type OtherElement
207 * The vectors are divided element-wise
208 */
209 template<typename OtherElement>
210 BasicVector4<Element> operator/ (const BasicVector4<OtherElement>& other) const
211 {
212 return BasicVector4<Element> (m_elements[0] / static_cast<Element> (other.x()), m_elements[1]
213 / static_cast<Element> (other.y()), m_elements[2] / static_cast<Element> (other.z()), m_elements[3]
214 / static_cast<Element> (other.w()));
215 }
216
217 template<typename OtherElement>
218 void operator/= (const BasicVector4<OtherElement>& other)
219 {
220 m_elements[0] /= static_cast<Element> (other.x());
221 m_elements[1] /= static_cast<Element> (other.y());
222 m_elements[2] /= static_cast<Element> (other.z());
223 m_elements[3] /= static_cast<Element> (other.w());
224 }
225
226 /* Define the scalar divisions / and /=
227 */
228 template<typename OtherElement>
229 BasicVector4<Element> operator/ (const OtherElement& other) const
230 {
231 Element divisor = static_cast<Element> (other);
232 return BasicVector4<Element> (m_elements[0] / divisor, m_elements[1] / divisor, m_elements[2] / divisor,
233 m_elements[3] / divisor);
234 }
235
236 template<typename OtherElement>
237 void operator/= (const OtherElement& other)
238 {
239 Element divisor = static_cast<Element> (other);
240 m_elements[0] /= divisor;
241 m_elements[1] /= divisor;
242 m_elements[2] /= divisor;
243 m_elements[3] /= divisor;
244 }
245
246 /* Scalar product this vector with another Vector4,
247 * returning the projection of <self> onto <other>
248 *
249 * @param other
250 * The Vector4 to dot-product with this Vector4.
251 *
252 * @returns
253 * The inner product (a scalar): a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]
254 */
255
256 template<typename OtherT>
dot(const BasicVector4<OtherT> & other)257 Element dot (const BasicVector4<OtherT>& other) const
258 {
259 return Element(m_elements[0] * other.x() + m_elements[1] * other.y() + m_elements[2] * other.z()
260 + m_elements[3] * other.w());
261 }
262
263 /** Project this homogeneous Vector4 into a Cartesian Vector3
264 * by dividing by w.
265 *
266 * @returns
267 * A Vector3 representing the Cartesian equivalent of this
268 * homogeneous vector.
269 */
getProjected()270 BasicVector3<Element> getProjected ()
271 {
272 return BasicVector3<Element> (m_elements[0] / m_elements[3], m_elements[1] / m_elements[3], m_elements[2]
273 / m_elements[3]);
274 }
275
276 /**
277 * @return String representation of the vector - values are separated by space
278 */
toString()279 std::string toString () const
280 {
281 std::stringstream ss;
282 ss << m_elements[0] << " " << m_elements[1] << " " << m_elements[2] << " " << m_elements[3];
283 return ss.str();
284 }
285
286 /** Cast to std::string
287 */
string()288 operator std::string() const {
289 return toString();
290 }
291
292 /** Implicit cast to C-style array. This allows a Vector4 to be
293 * passed directly to GL functions that expect an array (e.g.
294 * glFloat4fv()). These functions implicitly provide operator[]
295 * as well, since the C-style array provides this function.
296 */
297
298 operator const Element* () const
299 {
300 return m_elements;
301 }
302
303 operator Element* ()
304 {
305 return m_elements;
306 }
307
308 /* Cast this Vector4 onto a Vector3, both const and non-const
309 */
getVector3()310 BasicVector3<Element>& getVector3 ()
311 {
312 return *reinterpret_cast<BasicVector3<Element>*> (m_elements);
313 }
314
getVector3()315 const BasicVector3<Element>& getVector3 () const
316 {
317 return *reinterpret_cast<const BasicVector3<Element>*> (m_elements);
318 }
319
320 }; // BasicVector4
321
322 // ==========================================================================================
323
324 // A 4-element vector stored in single-precision floating-point.
325 typedef BasicVector4<float> Vector4;
326
327 // =============== Common Vector4 Methods ==================================================
328
329 template<typename Element, typename OtherElement>
vector4_equal_epsilon(const BasicVector4<Element> & self,const BasicVector4<OtherElement> & other,Element epsilon)330 inline bool vector4_equal_epsilon (const BasicVector4<Element>& self, const BasicVector4<OtherElement>& other,
331 Element epsilon)
332 {
333 return float_equal_epsilon(self.x(), other.x(), epsilon) && float_equal_epsilon(self.y(), other.y(), epsilon)
334 && float_equal_epsilon(self.z(), other.z(), epsilon) && float_equal_epsilon(self.w(), other.w(), epsilon);
335 }
336