BRL-CAD
dvec.h
Go to the documentation of this file.
1/* D V E C . H
2 * BRL-CAD
3 *
4 * Copyright (c) 2008-2023 United States Government as represented by
5 * the U.S. Army Research Laboratory.
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 License
9 * version 2.1 as published by the Free Software Foundation.
10 *
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this file; see the file named COPYING for more
18 * information.
19 */
20
21#ifndef BN_DVEC_H
22#define BN_DVEC_H
23
24#include "common.h"
25
26#include <math.h>
27extern "C++" {
28/* Hide iostream from Doxygen with cond */
29/** @cond */
30#include <iostream>
31#include <ostream>
32/** @endcond */
33}
34
35/* Needed for fastf_t definition */
36#include "bu/defines.h"
37
38/* Needed for VUNITIZE_TOL and NEAR_ZERO */
39#include "vmath.h"
40
41/** @addtogroup bn_vectormath */
42/** @{ */
43/** @file bn/dvec.h */
44
45extern "C++" {
46
47const double VEQUALITY = 0.0000001;
48
49template<int LEN>
51
52template<int LEN>
54
55template<int LEN>
56class dvec;
57
58template<int LEN>
59std::ostream& operator<<(std::ostream& out, const dvec<LEN>& v);
60
61class dvec_unop {
62public:
63 virtual double operator()(double a) const = 0;
64 virtual ~dvec_unop() {}
65};
66
67class dvec_op {
68public:
69 virtual double operator()(double a, double b) const = 0;
70 virtual ~dvec_op() {}
71};
72
73template<int LEN>
74class dvec {
75public:
76 dvec(double s);
77 dvec(const double* vals);
78 dvec(const float* vals);
79 dvec(const dvec<LEN>& p);
80
82 double operator[](int index) const;
83 void u_store(double* arr) const;
84 void u_store(float* arr) const;
85 void a_store(double* arr) const;
86 void a_store(float* arr) const;
87
88 bool operator==(const dvec<LEN>& b) const;
89
94
95 dvec<LEN> madd(const dvec<LEN>& s, const dvec<LEN>& b);
96 dvec<LEN> madd(const double s, const dvec<LEN>& b);
97
98 dvec<LEN> map(const dvec_unop& operation, int limit = LEN);
99 double foldr(double proto, const dvec_op& operation, int limit = LEN);
100 double foldl(double proto, const dvec_op& operation, int limit = LEN);
101
102 class mul : public dvec_op {
103 public:
104 double operator()(double a, double b) const { return a * b; }
105 };
106
107 class add : public dvec_op {
108 public:
109 double operator()(double a, double b) const { return a + b; }
110 };
111
112 class sub : public dvec_op {
113 public:
114 double operator()(double a, double b) const { return a - b; }
115 };
116
117 class sqrt : public dvec_unop {
118 public:
119 double operator()(double a) const { return ::sqrt(a); }
120 };
121private:
123
124 dvec(const dvec_internal<LEN>& d);
125 dvec(const fvec_internal<LEN>& f);
126};
127
128//#define DVEC4(V, t, a, b, c, d) double v#t[4] VEC_ALIGN = {(a), (b), (c), (d)}; V(v#t)
129
130// use this to create 16-byte aligned memory on platforms that support it
131#define VEC_ALIGN
132
133/* Doxygen doesn't like these includes... */
134/** @cond */
135/*#undef __SSE2__*/ // Test FPU version
136#if defined(__SSE2__) && defined(__GNUC__) && defined(HAVE_EMMINTRIN_H) && defined(HAVE_EMMINTRIN)
137# define __x86_vector__
138
139#ifdef HAVE_EMMINTRIN_H
140# include <emmintrin.h>
141#endif
142
143#undef VEC_ALIGN
144#define VEC_ALIGN __attribute__((aligned(16)))
145
146typedef double v2df __attribute__((vector_size(16)));
147typedef double v2f __attribute__((vector_size(8)));
148
149template<int LEN>
150struct dvec_internal {
151 v2df v[LEN/2];
152};
153
154template<int LEN>
155struct fvec_internal {
156 v2f v[LEN/2];
157};
158
159template<int LEN>
160inline dvec<LEN>::dvec(double s)
161{
162 double t[LEN] VEC_ALIGN;
163 for (int i = 0; i < LEN/2; i++) {
164 t[i*2] = s;
165 t[i*2+1] = s;
166 data.v[i] = _mm_load_pd(&t[i*2]);
167 }
168}
169
170template<int LEN>
171inline dvec<LEN>::dvec(const double* vals)
172{
173 for (int i = 0; i < LEN/2; i++) {
174 /* NOTE: assumes that vals are 16-byte aligned */
175 data.v[i] = _mm_load_pd(&vals[i*2]);
176 }
177}
178
179template<int LEN>
180inline dvec<LEN>::dvec(const dvec<LEN>& p)
181{
182 for (int i = 0; i < LEN/2; i++) {
183 data.v[i] = p.data.v[i];
184 }
185}
186
187template<int LEN>
188inline dvec<LEN>::dvec(const dvec_internal<LEN>& d)
189{
190 for (int i = 0; i < LEN/2; i++) data.v[i] = d.v[i];
191}
192
193template<int LEN>
194inline dvec<LEN>::dvec(const fvec_internal<LEN>& f)
195{
196 for (int i = 0; i < LEN/2; i++) data.v[i] = f.v[i];
197}
198
199template<int LEN>
200inline dvec<LEN>&
202{
203 for (int i = 0; i < LEN/2; i++) {
204 data.v[i] = p.data.v[i];
205 }
206 return *this;
207}
208
209template<int LEN>
210inline double
211dvec<LEN>::operator[](const int index) const
212{
213 double t[2] __attribute__((aligned(16)));
214 _mm_store_pd(t, data.v[index/2]);
215 return t[index%2];
216}
217
218template<int LEN>
219inline void
220dvec<LEN>::u_store(double* arr) const
221{
222 for (int i = 0; i < LEN/2; i++) {
223 _mm_storeu_pd(&arr[i*2], data.v[i]);
224 }
225}
226
227template<int LEN>
228inline void
229dvec<LEN>::a_store(double* arr) const
230{
231 for (int i = 0; i < LEN/2; i++) {
232 _mm_store_pd(&arr[i*2], data.v[i]);
233 }
234}
235
236template<int LEN>
237inline bool
238dvec<LEN>::operator==(const dvec<LEN>& b) const
239{
240 double ta[LEN] VEC_ALIGN;
241 double tb[LEN] VEC_ALIGN;
242 a_store(ta);
243 b.a_store(tb);
244 for (int i = 0; i < LEN; i++)
245 if (fabs(ta[i]-tb[i]) > VEQUALITY) return false;
246 return true;
247}
248
249#define DOP_IMPL(__op__) { \
250 dvec_internal<LEN> result; \
251 for (int i = 0; i < LEN/2; i++) { \
252 result.v[i] = __op__(data.v[i], b.data.v[i]); \
253 } \
254 return dvec<LEN>(result); \
255 }
256
257template<int LEN>
258inline dvec<LEN>
260{
261 DOP_IMPL(_mm_add_pd);
262}
263
264template<int LEN>
265inline dvec<LEN>
267{
268 DOP_IMPL(_mm_sub_pd);
269}
270
271template<int LEN>
272inline dvec<LEN>
274{
275 DOP_IMPL(_mm_mul_pd);
276}
277
278template<int LEN>
279inline dvec<LEN>
281{
282 DOP_IMPL(_mm_div_pd);
283}
284
285template<int LEN>
286inline dvec<LEN>
287dvec<LEN>::madd(const dvec<LEN>& s, const dvec<LEN>& b)
288{
290 for (int i = 0; i < LEN/2; i++) {
291 r.v[i] = _mm_mul_pd(data.v[i], s.data.v[i]);
292 }
293 for (int i = 0; i < LEN/2; i++) {
294 r.v[i] = _mm_add_pd(r.v[i], b.data.v[i]);
295 }
296 return dvec<LEN>(r);
297}
298
299template<int LEN>
300inline dvec<LEN>
301dvec<LEN>::madd(const double s, const dvec<LEN>& b)
302{
303 double _t[LEN] VEC_ALIGN;
304 for (int i = 0; i < LEN; i++) _t[i] = s;
305 dvec<LEN> t(_t);
306 return madd(t, b);
307}
308
309template<int LEN>
310inline double
311dvec<LEN>::foldr(double identity, const dvec_op& op, int limit)
312{
313 double _t[LEN] VEC_ALIGN;
314 a_store(_t);
315 double val = identity;
316 for (int i = limit-1; i >= 0; i--) {
317 val = op(_t[i], val);
318 }
319 return val;
320}
321
322template<int LEN>
323inline double
324dvec<LEN>::foldl(double identity, const dvec_op& op, int limit)
325{
326 double _t[LEN] VEC_ALIGN;
327 a_store(_t);
328 double val = identity;
329 for (int i = 0; i < limit; i++) {
330 val = op(val, _t[i]);
331 }
332 return val;
333}
334
335
336template<int LEN>
337inline dvec<LEN>
338dvec<LEN>::map(const dvec_unop& op, int limit)
339{
340 double _t[LEN] VEC_ALIGN;
341 a_store(_t);
342 for (int i = 0; i < limit; i++) {
343 _t[i] = op(_t[i]);
344 }
345 return dvec<LEN>(_t);
346}
347
348
349template <int LEN>
350inline std::ostream&
351operator<<(std::ostream& out, const dvec<LEN>& v)
352{
353 double _t[LEN] VEC_ALIGN;
354 v.a_store(_t);
355 out << "<";
356 for (int i = 0; i < LEN; i++) {
357 out << _t[i];
358 if (i != LEN-1)
359 out << ",";
360 }
361 out << ">";
362 return out;
363}
364
365class vec2d {
366public:
367
368 vec2d() {
369 _init(0, 0);
370 }
371
372 vec2d(double x_, double y_) {
373 _init(x_, y_);
374 }
375
376 vec2d(const vec2d& proto) {
377 _vec = proto._vec;
378 }
379
380 vec2d& operator=(const vec2d& b) {
381 _vec = b._vec;
382 return *this;
383 }
384
385 double operator[](int index) const {
386 double v[2] __attribute__((aligned(16)));
387 _mm_store_pd(v, _vec);
388 return v[index];
389 }
390
391 void ustore(double* arr) const {
392 // assume nothing about the alignment of arr
393 double v[2] __attribute__((aligned(16)));
394 _mm_store_pd(v, _vec);
395 arr[0] = v[0];
396 arr[1] = v[1];
397 }
398
399 double x() const { return (*this)[0]; }
400 double y() const { return (*this)[1]; }
401
402 vec2d operator+(const vec2d& b) const {
403 return vec2d(_mm_add_pd(_vec, b._vec));
404 }
405
406 vec2d operator-(const vec2d& b) const {
407 return vec2d(_mm_sub_pd(vec(), b.vec()));
408 }
409
410 vec2d operator*(const vec2d& b) const {
411 return vec2d(_mm_mul_pd(vec(), b.vec()));
412 }
413
414 vec2d operator/(const vec2d& b) const {
415 return vec2d(_mm_div_pd(vec(), b.vec()));
416 }
417
418 vec2d madd(const double& scalar, const vec2d& b) const {
419 return madd(vec2d(scalar, scalar), b);
420 }
421
422 vec2d madd(const vec2d& s, const vec2d& b) const {
423 return vec2d(_mm_add_pd(_mm_mul_pd(vec(), s.vec()), b.vec()));
424 }
425
426private:
427 //double v[2] __attribute__((aligned(16)));
428 v2df _vec;
429
430 vec2d(const v2df& result) {
431 _vec = result;
432 }
433
434 v2df vec() const { return _vec; }
435
436 void _init(double x_, double y_) {
437 double v[2] __attribute__((aligned(16)));
438 v[0] = x_;
439 v[1] = y_;
440 _vec = _mm_load_pd(v);
441 }
442
443};
444
445inline std::ostream&
446operator<<(std::ostream& out, const vec2d& v)
447{
448 out << "<" << v.x() << "," << v.y() << ">";
449 return out;
450}
451
452#else
453# define __fpu_vector__
454
455#ifdef __GNUC__
456#undef VEC_ALIGN
457#define VEC_ALIGN __attribute__((aligned(16)))
458#endif
459
460template<int LEN>
461struct dvec_internal {
462 double v[LEN] VEC_ALIGN;
463};
464
465template<int LEN>
466struct fvec_internal {
467 float v[LEN] VEC_ALIGN;
468};
469
470template<int LEN>
471inline dvec<LEN>::dvec(double s)
472{
473 for (int i = 0; i < LEN; i++)
474 data.v[i] = s;
475}
476
477template<int LEN>
478inline dvec<LEN>::dvec(const float* vals)
479{
480 for (int i = 0; i < LEN; i++)
481 data.v[i] = vals[i];
482}
483
484template<int LEN>
485inline dvec<LEN>::dvec(const double* vals)
486{
487 for (int i = 0; i < LEN; i++)
488 data.v[i] = vals[i];
489}
490
491template<int LEN>
492inline dvec<LEN>::dvec(const dvec<LEN>& p)
493{
494 for (int i = 0; i < LEN; i++)
495 data.v[i] = p.data.v[i];
496}
497
498template<int LEN>
499inline dvec<LEN>::dvec(const dvec_internal<LEN>& d)
500{
501 for (int i = 0; i < LEN; i++)
502 data.v[i] = d.v[i];
503}
504
505template<int LEN>
506inline dvec<LEN>::dvec(const fvec_internal<LEN>& f)
507{
508 for (int i = 0; i < LEN; i++)
509 data.v[i] = f.v[i];
510}
511
512template<int LEN>
513inline dvec<LEN>&
515{
516 for (int i = 0; i < LEN; i++)
517 data.v[i] = p.data.v[i];
518 return *this;
519}
520
521template<int LEN>
522inline double
523dvec<LEN>::operator[](int index) const
524{
525 return data.v[index];
526}
527
528template<int LEN>
529inline void
530dvec<LEN>::u_store(float* arr) const
531{
532 a_store(arr);
533}
534
535template<int LEN>
536inline void
537dvec<LEN>::u_store(double* arr) const
538{
539 a_store(arr);
540}
541
542template<int LEN>
543inline void
544dvec<LEN>::a_store(float* arr) const
545{
546 for (int i = 0; i < LEN; i++)
547 arr[i] = data.v[i];
548}
549
550template<int LEN>
551inline void
552dvec<LEN>::a_store(double* arr) const
553{
554 for (int i = 0; i < LEN; i++)
555 arr[i] = data.v[i];
556}
557
558template<int LEN>
559inline bool
560dvec<LEN>::operator==(const dvec<LEN>& b) const
561{
562 for (int i = 0; i < LEN; i++)
563 if (fabs(data.v[i]-b.data.v[i]) > VEQUALITY) return false;
564 return true;
565}
566
567template<int LEN>
568inline dvec<LEN>
570{
572 for (int i = 0; i < LEN; i++)
573 r.v[i] = data.v[i] + b.data.v[i];
574 return dvec<LEN>(r);
575}
576
577template<int LEN>
578inline dvec<LEN>
580{
582 for (int i = 0; i < LEN; i++)
583 r.v[i] = data.v[i] - b.data.v[i];
584 return dvec<LEN>(r);
585}
586
587template<int LEN>
588inline dvec<LEN>
590{
592 for (int i = 0; i < LEN; i++)
593 r.v[i] = data.v[i] * b.data.v[i];
594 return dvec<LEN>(r);
595}
596
597template<int LEN>
598inline dvec<LEN>
600{
602 for (int i = 0; i < LEN; i++)
603 r.v[i] = data.v[i] / b.data.v[i];
604 return dvec<LEN>(r);
605}
606
607template<int LEN>
608inline dvec<LEN>
609dvec<LEN>::madd(const dvec<LEN>& s, const dvec<LEN>& b)
610{
612 for (int i = 0; i < LEN; i++)
613 r.v[i] = data.v[i] * s.data.v[i] + b.data.v[i];
614 return dvec<LEN>(r);
615}
616
617template<int LEN>
618inline dvec<LEN>
619dvec<LEN>::madd(const double s, const dvec<LEN>& b)
620{
622 for (int i = 0; i < LEN; i++)
623 r.v[i] = data.v[i] * s + b.data.v[i];
624 return dvec<LEN>(r);
625}
626
627template<int LEN>
628inline double
629dvec<LEN>::foldr(double identity, const dvec_op& op, int limit)
630{
631 double val = identity;
632 for (int i = limit-1; i >= 0; i--) {
633 val = op(data.v[i], val);
634 }
635 return val;
636}
637template<int LEN>
638inline double
639dvec<LEN>::foldl(double identity, const dvec_op& op, int limit)
640{
641 double val = identity;
642 for (int i = 0; i < limit; i++) {
643 val = op(val, data.v[i]);
644 }
645 return val;
646}
647
648template<int LEN>
649inline dvec<LEN>
650dvec<LEN>::map(const dvec_unop& op, int limit)
651{
653 for (int i = 0; i < limit; i++) {
654 r.v[i] = op(data.v[i]);
655 }
656 return dvec<LEN>(r);
657}
658
659
660template <int LEN>
661inline std::ostream&
662operator<<(std::ostream& out, const dvec<LEN>& v)
663{
664 out << "<";
665 for (int i = 0; i < LEN; i++) {
666 out << v.data.v[i];
667 if (i != LEN-1)
668 out << ",";
669 }
670 out << ">";
671 return out;
672}
673
674class vec2d {
675public:
676
677 vec2d() {
678 _init(0, 0);
679 }
680
681 vec2d(double xin, double yin) {
682 _init(xin, yin);
683 }
684
685 vec2d(const vec2d& proto) {
686 _init(proto.v[0], proto.v[1]);
687 }
688
689 vec2d& operator=(const vec2d& b) {
690 v[0] = b.v[0];
691 v[1] = b.v[1];
692 return *this;
693 }
694
695 double operator[](int index) const { return v[index]; }
696
697 double x() const { return v[0]; }
698 double y() const { return v[1]; }
699
700 vec2d operator+(const vec2d& b) const {
701 return vec2d(v[0] + b.v[0], v[1] + b.v[1]);
702 }
703
704 vec2d operator-(const vec2d& b) const {
705 return vec2d(v[0] - b.v[0], v[1] - b.v[1]);
706 }
707
708 vec2d operator*(const vec2d& b) const {
709 return vec2d(v[0] * b.v[0], v[1] * b.v[1]);
710 }
711
712 vec2d operator/(const vec2d& b) const {
713 return vec2d(v[0] / b.v[0], v[1] / b.v[1]);
714 }
715
716 vec2d madd(const double& scalar, const vec2d& b) const {
717 return vec2d(v[0]*scalar+b.v[0], v[1]*scalar+b.v[1]);
718 }
719
720 vec2d madd(const vec2d& s, const vec2d& b) const {
721 return vec2d(v[0]*s.v[0]+b.v[0], v[1]*s.v[1]+b.v[1]);
722 }
723
724private:
725 double* v;
726 double m[4];
727
728 void _init(double xin, double yin) {
729 // align to 16-byte boundary
730 v = (double*)((((uintptr_t)m) + 0x10L) & ~0xFL);
731 v[0] = xin;
732 v[1] = yin;
733 }
734};
735
736inline std::ostream&
737operator<<(std::ostream& out, const vec2d& v)
738{
739 out << "<" << v.x() << "," << v.y() << ">";
740 return out;
741}
742
743#endif
744/** @endcond */
745
746inline bool vequals(const vec2d& a, const vec2d& b) {
747 return
748 (fabs(a.x()-b.x()) < VEQUALITY) &&
749 (fabs(a.y()-b.y()) < VEQUALITY);
750}
751
752// 2x2 row-major matrix
753typedef fastf_t mat2d_t[4] VEC_ALIGN;
754
755/* Hide from Doxygen with cond */
756/** @cond */
757
758// 2d point
759typedef fastf_t pt2d_t[2] VEC_ALIGN;
760
761/** @endcond */
762
763//--------------------------------------------------------------------------------
764// MATH / VECTOR ops
765inline
766bool mat2d_inverse(mat2d_t inv, mat2d_t m) {
767 pt2d_t _a = {m[0], m[1]};
768 pt2d_t _b = {m[3], m[2]};
769 dvec<2> a(_a);
770 dvec<2> b(_b);
771 dvec<2> c = a*b;
772 fastf_t det = c.foldr(0, dvec<2>::sub());
773 if (NEAR_ZERO(det, VUNITIZE_TOL)) return false;
774 fastf_t scale = 1.0 / det;
775 double tmp[4] VEC_ALIGN = {m[3], -m[1], -m[2], m[0]};
776 dvec<4> iv(tmp);
777 dvec<4> sv(scale);
778 dvec<4> r = iv * sv;
779 r.a_store(inv);
780 return true;
781}
782inline
783void mat2d_pt2d_mul(pt2d_t r, mat2d_t m, pt2d_t p) {
784 pt2d_t _a = {m[0], m[2]};
785 pt2d_t _b = {m[1], m[3]};
786 dvec<2> x(p[0]);
787 dvec<2> y(p[1]);
788 dvec<2> a(_a);
789 dvec<2> b(_b);
790 dvec<2> c = a*x + b*y;
791 c.a_store(r);
792}
793inline
794void pt2dsub(pt2d_t r, pt2d_t a, pt2d_t b) {
795 dvec<2> va(a);
796 dvec<2> vb(b);
797 dvec<2> vr = va - vb;
798 vr.a_store(r);
799}
800
801inline
802fastf_t v2mag(pt2d_t p) {
803 dvec<2> a(p);
804 dvec<2> sq = a*a;
805 return sqrt(sq.foldr(0, dvec<2>::add()));
806}
807
808inline
809void move(pt2d_t a, const double *b) {
810 a[0] = b[0];
811 a[1] = b[1];
812}
813}
814
815/** @} */
816
817#endif /* BN_DVEC_H */
818
819/*
820 * Local Variables:
821 * tab-width: 8
822 * mode: C
823 * indent-tabs-mode: t
824 * c-file-style: "stroustrup"
825 * End:
826 * ex: shiftwidth=4 tabstop=8
827 */
double operator()(double a, double b) const
Definition: dvec.h:109
double operator()(double a, double b) const
Definition: dvec.h:104
double operator()(double a) const
Definition: dvec.h:119
double operator()(double a, double b) const
Definition: dvec.h:114
Definition: dvec.h:67
virtual double operator()(double a, double b) const =0
virtual ~dvec_op()
Definition: dvec.h:70
Definition: dvec.h:61
virtual double operator()(double a) const =0
virtual ~dvec_unop()
Definition: dvec.h:64
Definition: dvec.h:74
dvec(const float *vals)
dvec(const double *vals)
void u_store(double *arr) const
dvec< LEN > operator-(const dvec< LEN > &b)
double foldr(double proto, const dvec_op &operation, int limit=LEN)
dvec< LEN > operator+(const dvec< LEN > &b)
void a_store(double *arr) const
dvec< LEN > madd(const double s, const dvec< LEN > &b)
dvec(const dvec< LEN > &p)
dvec(double s)
dvec< LEN > & operator=(const dvec< LEN > &p)
dvec< LEN > madd(const dvec< LEN > &s, const dvec< LEN > &b)
bool operator==(const dvec< LEN > &b) const
void a_store(float *arr) const
dvec< LEN > operator/(const dvec< LEN > &b)
dvec< LEN > operator*(const dvec< LEN > &b)
double operator[](int index) const
double foldl(double proto, const dvec_op &operation, int limit=LEN)
void u_store(float *arr) const
dvec< LEN > map(const dvec_unop &operation, int limit=LEN)
Header file for the BRL-CAD common definitions.
fastf_t mat2d_t[4] VEC_ALIGN
Definition: dvec.h:753
void pt2dsub(pt2d_t r, pt2d_t a, pt2d_t b)
Definition: dvec.h:794
fastf_t v2mag(pt2d_t p)
Definition: dvec.h:802
std::ostream & operator<<(std::ostream &out, const dvec< LEN > &v)
void mat2d_pt2d_mul(pt2d_t r, mat2d_t m, pt2d_t p)
Definition: dvec.h:783
bool mat2d_inverse(mat2d_t inv, mat2d_t m)
Definition: dvec.h:766
const double VEQUALITY
Definition: dvec.h:47
bool vequals(const vec2d &a, const vec2d &b)
Definition: dvec.h:746
#define VEC_ALIGN
Definition: dvec.h:131
void move(pt2d_t a, const double *b)
Definition: dvec.h:809
void int float float float * scale
Definition: tig.h:142
void float float * y
Definition: tig.h:73
void int * c
Definition: tig.h:139
void float * x
Definition: tig.h:72
#define __attribute__(ignore)
Definition: common.h:295
double fastf_t
fastest 64-bit (or larger) floating point type
Definition: vmath.h:330
#define NEAR_ZERO(val, epsilon)
Definition: vmath.h:461
#define VUNITIZE_TOL
Definition: vmath.h:295
fundamental vector, matrix, quaternion math macros