1 #ifndef CLUNK_V3_H__
2 #define CLUNK_V3_H__
3 
4 /* clunk - cross-platform 3D audio API built on top SDL library
5  * Copyright (C) 2007-2014 Netive Media Group
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11 
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 
22 #include <clunk/types.h>
23 #include <limits>
24 
25 namespace clunk {
26 /*!
27 	\brief 3d vector
28 	\tparam T type of the axis. usually int or float.
29 */
30 template <typename T> struct v3  {
31 	typedef std::numeric_limits<T> limits_type;
32 
33 	template<typename V>
absv334 	static inline V abs(V v) { return v < 0? -v: v; }
35 
36 	///x component
37 	T x;
38 	///y component
39 	T y;
40 	///z component
41 	T z;
42 	///default ctor: initializes all components with zeroes.
43 	inline v3<T>() : x(0), y(0), z(0) {}
44 	///initializes all components with given values
xv345 	inline v3<T>(const T x, const T y, const T z) : x(x), y(y), z(z) {}
46 
47 	///nullify vector
clearv348 	inline void clear() { x = y = z = 0; }
49 	///returns true if x == y == z == 0 ?
is0v350 	inline bool is0() const {
51 		T zero = limits_type::epsilon();
52 		return abs(x) <= zero && abs(y) <= zero && abs(z) <= zero;
53 	}
54 
55 	/*!
56 		\brief normalizes vector.
57 		\return old length of this vector
58 	*/
normalizev359 	inline T normalize() {
60 		const T len = length();
61 		if (len == (T)0 || len ==(T)1)
62 			return len;
63 
64 		x /= len;
65 		y /= len;
66 		z /= len;
67 		return len;
68 	}
69 
70 	/*!
71 		\brief normalizes vector with given length
72 		\param[in] nlen length
73 		\return old length of this vector
74 	*/
75 
normalizev376 	inline T normalize(const T nlen) {
77 		const T len = length();
78 		if (len == (T)0 || len == nlen)
79 			return len;
80 
81 		x *= nlen / len;
82 		y *= nlen / len;
83 		z *= nlen / len;
84 		return len;
85 	}
86 
dot_productv387 	inline T dot_product(const v3<T> &v) const {
88 		return x * v.x + y * v.y + z * v.z;
89 	}
90 
cross_productv391 	inline v3<T> cross_product(const v3<T> &v) const {
92 		return v3<T>(
93 			y * v.z - z * v.y,
94 			z * v.x - x * v.z,
95 			x * v.y - y * v.x
96 		);
97 	}
98 
99 	///returns length of this vector
lengthv3100 	inline T length() const {
101 		const T ql = x * x + y * y + z * z;
102 		if (ql == (T)0 || ql == (T)1)
103 				return ql;
104 
105 		return (T)sqrt(ql);
106 	}
107 	///returns square of length. To avoid sqrt if needed.
quick_lengthv3108 	inline T quick_length() const {
109 		return (T)(x * x + y * y + z * z);
110 	}
111 
112 	///converts to vector of another type
113 	template <typename T2>
convertv3114 		inline v3<T2> convert() const { return v3<T2>((T2)x, (T2)y, (T2)z); }
115 
116 	///returns distance between two points
distancev3117 	inline T distance(const v3<T>& other) const {
118 		v3<T>d(*this);
119 		d -= other;
120 		return d.length();
121 	}
122 
123 	///return square distance between two points
quick_distancev3124 	inline T quick_distance(const v3<T>& other) const {
125 		const T dx = x - other.x;
126 		const T dy = y - other.y;
127 		const T dz = z - other.z;
128 		return (dx * dx + dy * dy + dz * dz);
129 	}
130 
131 	///allows v3 be placed in sorted STL container such std::map
132 	inline bool operator<(const v3<T> &other) const {
133 		if (x != other.x) {
134 			return x < other.x;
135 		}
136 		if (y != other.y) {
137 			return y < other.y;
138 		}
139 		return z < other.z;
140 	}
141 
142 	///negate all components
143 	inline v3<T> operator-() const {
144 		return v3<T>(-x, -y, -z);
145 	}
146 	///test equality
147 	inline bool operator==(const v3<T> &other) const {
148 		return x == other.x && y == other.y && z == other.z;
149 	}
150 
151 	///test inequality
152 	inline bool operator!=(const v3<T> &other) const {
153 		return x != other.x || y != other.y || z != other.z;
154 	}
155 
156 	///adds another vector
157 	inline v3<T>& operator+=(const v3<T>& other) {
158 		x += other.x; y += other.y; z += other.z;
159 		return *this;
160 	}
161 
162 	///substracts another vector
163 	inline v3<T>& operator-=(const v3<T>& other) {
164 		x -= other.x; y -= other.y; z -= other.z;
165 		return *this;
166 	}
167 
168 	///multiplies another vector
169 	inline v3<T>& operator*=(const v3<T>& other) {
170 		x *= other.x; y *= other.y; z *= other.z;
171 		return *this;
172 	}
173 
174 	///divide with another vector
175 	inline v3<T>& operator/=(const v3<T>& other) {
176 		x /= other.x; y /= other.y; z /= other.z;
177 		return *this;
178 	}
179 	///multiplication
180 	inline v3<T> operator*(const v3<T>& other) const {
181 		return v3<T>(x * other.x, y * other.y, z * other.z);
182 	}
183 	///summing
184 	inline v3<T> operator+(const v3<T>& other) const {
185 		return v3<T>(x + other.x, y + other.y, z + other.z);
186 	}
187 	///substraction
188 	inline v3<T> operator-(const v3<T>& other) const {
189 		return v3<T>(x - other.x, y - other.y, z - other.z);
190 	}
191 	///division
192 	inline v3<T> operator/(const v3<T>& other) const {
193 		return v3<T>(x / other.x, y / other.y, z / other.z);
194 	}
195 	///multiplies all components with constant
196 	inline v3<T> operator*(const T& other) const {
197 		return v3<T>(x * other, y * other, z * other);
198 	}
199 	///sums all components with constant
200 	inline v3<T> operator+(const T& other) const {
201 		return v3<T>(x + other, y + other, z + other);
202 	}
203 	///substracts all components with constant
204 	inline v3<T> operator-(const T& other) const {
205 		return v3<T>(x - other, y - other, z - other);
206 	}
207 	///divides all components by constant
208 	inline v3<T> operator/(const T& other) const {
209 		return v3<T>(x / other, y / other, z / other);
210 	}
211 	///divides this vector by constant
212 	inline v3<T>& operator/=(const T& other) {
213 		x /= other;
214 		y /= other;
215 		z /= other;
216 		return *this;
217 	}
218 
219 	///multiplies this vector with constant
220 	inline v3<T>& operator*=(const T& other) {
221 		x *= other;
222 		y *= other;
223 		z *= other;
224 		return *this;
225 	}
226 
227 	///sums this vector with constant
228 	inline v3<T>& operator+=(const T& other) {
229 		x += other;
230 		y += other;
231 		z += other;
232 		return *this;
233 	}
234 
235 	///substracts this vector with constant
236 	inline v3<T>& operator-=(const T& other) {
237 		x -= other;
238 		y -= other;
239 		z -= other;
240 		return *this;
241 	}
242 
243 	///adds constant to the vector
244 	inline v3<T> operator+(const T a)  {
245 		return v3<T>(x + a, y + a, z + a);
246 	}
247 
248 	///subs constant from the vector
249 	inline v3<T> operator-(const T a)  {
250 		return v3<T>(x - a, y - a, z - a);
251 	}
252 
253 	///muls constant to the vector
254 	inline v3<T> operator*(const T a)  {
255 		return v3<T>(x * a, y * a, z * a);
256 	}
257 
258 	///divs constant to the vector
259 	inline v3<T> operator/(const T a)  {
260 		return v3<T>(x / a, y  / a, z / a);
261 	}
262 };
263 ///external operator+
264 template <typename T>
265 	inline v3<T> operator+(const T a, const v3<T> &v)  {
266 		return v3<T>(v.x + a, v.y + a, v.z + a);
267 	}
268 
269 ///external operator-
270 template <typename T>
271 	inline v3<T> operator-(const T a, const v3<T> &v)  {
272 		return v3<T>(a - v.x, a - v.y, a - v.z);
273 	}
274 
275 ///external operator*
276 template <typename T>
277 	inline v3<T> operator*(const T a, const v3<T> &v)  {
278 		return v3<T>(v.x * a, v.y * a, v.z * a);
279 	}
280 
281 ///external operator/
282 template <typename T>
283 	inline v3<T> operator/(const T a, const v3<T> &v)  {
284 		return v3<T>(a / v.x, a / v.y, a / v.z);
285 	}
286 
287 typedef v3<float> v3f;
288 
289 #if 0 //defined CLUNK_USES_SSE
290 #	include <xmmintrin.h>
291 
292 template <>
293 class v3<float>  {
294 	__m128 value;
295 
296 public:
297 
298 	template <int POS>
299 	class float_placeholder {
300 		__m128 &value;
301 	public:
302 		inline float_placeholder(__m128 &value) __attribute__((__always_inline__))  : value(value) {}
303 		inline float get() const __attribute__((__always_inline__)) {
304 			float r[4];
305 			_mm_storeu_ps(r, value);
306 			return r[POS];
307 		}
308 		inline void set(float v) __attribute__((__always_inline__)) {
309 			__m128 mask = _mm_cmpgt_ps(_mm_set_ps(POS == 2?1:0, POS == 1?1:0, POS == 0?1:0, 0), _mm_setzero_ps());
310 			value = _mm_or_ps(
311 				_mm_andnot_ps(mask, value),
312 				_mm_and_ps(mask, _mm_set1_ps(v))
313 			);
314 		}
315 
316 		inline operator float() const __attribute__((__always_inline__)) {
317 			return get();
318 		}
319 		inline const float_placeholder<POS>& operator=(const float_placeholder<POS> &other) __attribute__((__always_inline__)) {
320 			set(other.get());
321 			return *this;
322 		}
323 
324 		inline const float_placeholder<POS>& operator=(float v) __attribute__((__always_inline__)) {
325 			set(v);
326 			return *this;
327 		}
328 	};
329 	float_placeholder<0> x;
330 	float_placeholder<1> y;
331 	float_placeholder<2> z;
332 
333 	inline v3<float>(): value(_mm_setzero_ps()), x(value), y(value), z(value) {}
334 	inline v3<float>(__m128 v): value(v), x(value), y(value), z(value) {}
335 	inline v3<float>(const float xv, const float yv, const float zv) :
336 		value(_mm_set_ps(zv, yv, xv, 0)), x(value), y(value), z(value) {}
337 
338 	inline void clear() { value = _mm_setzero_ps(); }
339 
340 	inline const bool is0() const {
341 		return (_mm_movemask_ps(_mm_cmpeq_ps(value, _mm_setzero_ps())) & 7 ) == 7;
342 	}
343 
344 	inline const float normalize() {
345 		float len = length();
346 		if (len == (float)0 || len ==(float)1)
347 			return len;
348 
349 		value = _mm_div_ps(value, _mm_set1_ps(len));
350 		return len;
351 	}
352 
353 	inline const float normalize(const float nlen) {
354 		const float len = length();
355 		if (len == (float)0 || len == nlen)
356 			return len;
357 
358 		__m128 k = _mm_div_ps(_mm_set1_ps(nlen), _mm_set1_ps(len));
359 		value = _mm_div_ps(value, k);
360 		return len;
361 	}
362 
363 	inline const float dot_product(const v3<float> &v) const {
364 		float fixme[4];
365 		_mm_storeu_ps(fixme, _mm_mul_ps(value, v.value));
366 		return fixme[0] + fixme[1] + fixme[2] + fixme[3];
367 	}
368 
369 	inline const float length() const {
370 		float v[4];
371 		_mm_storeu_ps(v, _mm_mul_ps(value, value));
372 		const float ql = v[0] + v[1] + v[2];
373 		if (ql == 0 || ql == 1.0f)
374 			return ql;
375 
376 		return (float)sqrt(ql);
377 	}
378 
379 	inline float quick_length() const {
380 		float v[4];
381 		_mm_storeu_ps(v, _mm_mul_ps(value, value));
382 		return v[0] + v[1] + v[2];
383 	}
384 
385 	template <typename T2>
386 		inline v3<T2> convert() const {
387 			float v[4];
388 			_mm_storeu_ps(v, value);
389 			return v3<T2>((T2)v[0], (T2)v[1], (T2)v[2]);
390 		}
391 
392 	inline const float distance(const v3<float>& other) const {
393 		v3<float>d(*this);
394 		d -= other;
395 		return d.length();
396 	}
397 
398 	inline float quick_distance(const v3<float>& other) const {
399 		float v[4];
400 		__m128 dv = _mm_sub_ps(value, other.value);
401 		_mm_storeu_ps(v, _mm_mul_ps(dv, dv));
402 		return v[0] + v[1] + v[2];
403 	}
404 
405 	inline const bool operator<(const v3<float> &other) const {
406 		int c = _mm_movemask_ps(_mm_cmpneq_ps(value, other.value));
407 		int l = _mm_movemask_ps(_mm_cmplt_ps(value, other.value));
408 		if (c & 1) {
409 			return l & 1;
410 		}
411 		if (c & 2) {
412 			return l & 2;
413 		}
414 		return l & 4;
415 	}
416 
417 	inline const v3<float> operator-() const {
418 		return _mm_sub_ps(_mm_setzero_ps(), value);
419 	}
420 
421 	inline const bool operator==(const v3<float> &other) const {
422 		int mask = _mm_movemask_ps(_mm_cmpeq_ps(value, other.value));
423 		return (mask & 7) == 7;
424 	}
425 
426 	///test inequality
427 	inline const bool operator!=(const v3<float> &other) const {
428 		int mask = _mm_movemask_ps(_mm_cmpeq_ps(value, other.value));
429 		return (mask & 7) != 7;
430 	}
431 
432 	///adds another vector
433 	inline const v3<float>& operator+=(const v3<float>& other) {
434 		value = _mm_add_ps(value, other.value);
435 		return *this;
436 	}
437 
438 	///substracts another vector
439 	inline const v3<float>& operator-=(const v3<float>& other) {
440 		value = _mm_sub_ps(value, other.value);
441 		return *this;
442 	}
443 
444 	///multiplies another vector
445 	inline const v3<float>& operator*=(const v3<float>& other) {
446 		value = _mm_mul_ps(value, other.value);
447 		return *this;
448 	}
449 
450 	///divide with another vector
451 	inline const v3<float>& operator/=(const v3<float>& other) {
452 		value = _mm_div_ps(value, other.value);
453 		return *this;
454 	}
455 	///multiplication
456 	inline const v3<float> operator*(const v3<float>& other) const {
457 		return v3<float>(_mm_mul_ps(value, other.value));
458 	}
459 	///summing
460 	inline const v3<float> operator+(const v3<float>& other) const {
461 		return v3<float>(_mm_add_ps(value, other.value));
462 	}
463 	///substraction
464 	inline const v3<float> operator-(const v3<float>& other) const {
465 		return v3<float>(_mm_sub_ps(value, other.value));
466 	}
467 	///division
468 	inline const v3<float> operator/(const v3<float>& other) const {
469 		return v3<float>(_mm_div_ps(value, other.value));
470 	}
471 	///multiplies all components with constant
472 	inline const v3<float> operator*(const float& other) const {
473 		return v3<float>(_mm_mul_ps(value, _mm_set1_ps(other)));
474 	}
475 	///sums all components with constant
476 	inline const v3<float> operator+(const float& other) const {
477 		return v3<float>(_mm_add_ps(value, _mm_set1_ps(other)));
478 	}
479 	///substracts all components with constant
480 	inline const v3<float> operator-(const float& other) const {
481 		return v3<float>(_mm_sub_ps(value, _mm_set1_ps(other)));
482 	}
483 	///divides all components by constant
484 	inline const v3<float> operator/(const float& other) const {
485 		return v3<float>(_mm_div_ps(value, _mm_set1_ps(other)));
486 	}
487 	///divides this vector by constant
488 	inline const v3<float>& operator/=(const float& other) {
489 		value = _mm_div_ps(value, _mm_set1_ps(other));
490 		return *this;
491 	}
492 
493 	///multiplies this vector with constant
494 	inline const v3<float>& operator*=(const float& other) {
495 		value = _mm_mul_ps(value, _mm_set1_ps(other));
496 		return *this;
497 	}
498 
499 	///sums this vector with constant
500 	inline const v3<float>& operator+=(const float& other) {
501 		value = _mm_add_ps(value, _mm_set1_ps(other));
502 		return *this;
503 	}
504 
505 	///substracts this vector with constant
506 	inline const v3<float>& operator-=(const float& other) {
507 		value = _mm_sub_ps(value, _mm_set1_ps(other));
508 		return *this;
509 	}
510 
511 	///adds constant to the vector
512 	inline const v3<float> operator+(const float a)  {
513 		return v3<float>(_mm_add_ps(value, _mm_set1_ps(a)));
514 	}
515 
516 	///subs constant from the vector
517 	inline const v3<float> operator-(const float a)  {
518 		return v3<float>(_mm_sub_ps(value, _mm_set1_ps(a)));
519 	}
520 
521 	///muls constant to the vector
522 	inline const v3<float> operator*(const float a)  {
523 		return v3<float>(_mm_mul_ps(value, _mm_set1_ps(a)));
524 	}
525 
526 	///divs constant to the vector
527 	inline const v3<float> operator/(const float a)  {
528 		return v3<float>(_mm_div_ps(value, _mm_set1_ps(a)));
529 	}
530 };
531 
532 #endif //CLUNK_USES_SSE
533 
534 } //namespace clunk
535 
536 #endif
537 
538