Bullet Collision Detection & Physics Library
btScalar.h
Go to the documentation of this file.
1 /*
2 Copyright (c) 2003-2009 Erwin Coumans http://bullet.googlecode.com
3 
4 This software is provided 'as-is', without any express or implied warranty.
5 In no event will the authors be held liable for any damages arising from the use of this software.
6 Permission is granted to anyone to use this software for any purpose,
7 including commercial applications, and to alter it and redistribute it freely,
8 subject to the following restrictions:
9 
10 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
11 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
12 3. This notice may not be removed or altered from any source distribution.
13 */
14 
15 
16 
17 #ifndef BT_SCALAR_H
18 #define BT_SCALAR_H
19 
20 #ifdef BT_MANAGED_CODE
21 //Aligned data types not supported in managed code
22 #pragma unmanaged
23 #endif
24 
25 
26 #include <math.h>
27 #include <stdlib.h>//size_t for MSVC 6.0
28 #include <float.h>
29 
30 /* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/
31 #define BT_BULLET_VERSION 281
32 
33 inline int btGetVersion()
34 {
35  return BT_BULLET_VERSION;
36 }
37 
38 #if defined(DEBUG) || defined (_DEBUG)
39 #define BT_DEBUG
40 #endif
41 
42 
43 #ifdef _WIN32
44 
45  #if defined(__MINGW32__) || defined(__CYGWIN__) || (defined (_MSC_VER) && _MSC_VER < 1300)
46 
47  #define SIMD_FORCE_INLINE inline
48  #define ATTRIBUTE_ALIGNED16(a) a
49  #define ATTRIBUTE_ALIGNED64(a) a
50  #define ATTRIBUTE_ALIGNED128(a) a
51  #else
52  //#define BT_HAS_ALIGNED_ALLOCATOR
53  #pragma warning(disable : 4324) // disable padding warning
54 // #pragma warning(disable:4530) // Disable the exception disable but used in MSCV Stl warning.
55 // #pragma warning(disable:4996) //Turn off warnings about deprecated C routines
56 // #pragma warning(disable:4786) // Disable the "debug name too long" warning
57 
58  #define SIMD_FORCE_INLINE __forceinline
59  #define ATTRIBUTE_ALIGNED16(a) __declspec(align(16)) a
60  #define ATTRIBUTE_ALIGNED64(a) __declspec(align(64)) a
61  #define ATTRIBUTE_ALIGNED128(a) __declspec (align(128)) a
62  #ifdef _XBOX
63  #define BT_USE_VMX128
64 
65  #include <ppcintrinsics.h>
66  #define BT_HAVE_NATIVE_FSEL
67  #define btFsel(a,b,c) __fsel((a),(b),(c))
68  #else
69 
70 #if (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (BT_USE_DOUBLE_PRECISION))
71  #define BT_USE_SSE
72  #ifdef BT_USE_SSE
73  //BT_USE_SSE_IN_API is disabled under Windows by default, because
74  //it makes it harder to integrate Bullet into your application under Windows
75  //(structured embedding Bullet structs/classes need to be 16-byte aligned)
76  //with relatively little performance gain
77  //If you are not embedded Bullet data in your classes, or make sure that you align those classes on 16-byte boundaries
78  //you can manually enable this line or set it in the build system for a bit of performance gain (a few percent, dependent on usage)
79  //#define BT_USE_SSE_IN_API
80  #endif //BT_USE_SSE
81  #include <emmintrin.h>
82 #endif
83 
84  #endif//_XBOX
85 
86  #endif //__MINGW32__
87 
88 #ifdef BT_DEBUG
89  #ifdef _MSC_VER
90  #include <stdio.h>
91  #define btAssert(x) { if(!(x)){printf("Assert "__FILE__ ":%u ("#x")\n", __LINE__);__debugbreak(); }}
92  #else//_MSC_VER
93  #include <assert.h>
94  #define btAssert assert
95  #endif//_MSC_VER
96 #else
97  #define btAssert(x)
98 #endif
99  //btFullAssert is optional, slows down a lot
100  #define btFullAssert(x)
101 
102  #define btLikely(_c) _c
103  #define btUnlikely(_c) _c
104 
105 #else
106 
107 #if defined (__CELLOS_LV2__)
108  #define SIMD_FORCE_INLINE inline __attribute__((always_inline))
109  #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16)))
110  #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64)))
111  #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128)))
112  #ifndef assert
113  #include <assert.h>
114  #endif
115 #ifdef BT_DEBUG
116 #ifdef __SPU__
117 #include <spu_printf.h>
118 #define printf spu_printf
119  #define btAssert(x) {if(!(x)){printf("Assert "__FILE__ ":%u ("#x")\n", __LINE__);spu_hcmpeq(0,0);}}
120 #else
121  #define btAssert assert
122 #endif
123 
124 #else
125  #define btAssert(x)
126 #endif
127  //btFullAssert is optional, slows down a lot
128  #define btFullAssert(x)
129 
130  #define btLikely(_c) _c
131  #define btUnlikely(_c) _c
132 
133 #else
134 
135 #ifdef USE_LIBSPE2
136 
137  #define SIMD_FORCE_INLINE __inline
138  #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16)))
139  #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64)))
140  #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128)))
141  #ifndef assert
142  #include <assert.h>
143  #endif
144 #ifdef BT_DEBUG
145  #define btAssert assert
146 #else
147  #define btAssert(x)
148 #endif
149  //btFullAssert is optional, slows down a lot
150  #define btFullAssert(x)
151 
152 
153  #define btLikely(_c) __builtin_expect((_c), 1)
154  #define btUnlikely(_c) __builtin_expect((_c), 0)
155 
156 
157 #else
158  //non-windows systems
159 
160 #if (defined (__APPLE__) && (!defined (BT_USE_DOUBLE_PRECISION)))
161  #if defined (__i386__) || defined (__x86_64__)
162  #define BT_USE_SSE
163  //BT_USE_SSE_IN_API is enabled on Mac OSX by default, because memory is automatically aligned on 16-byte boundaries
164  //if apps run into issues, we will disable the next line
165  #define BT_USE_SSE_IN_API
166  #ifdef BT_USE_SSE
167  // include appropriate SSE level
168  #if defined (__SSE4_1__)
169  #include <smmintrin.h>
170  #elif defined (__SSSE3__)
171  #include <tmmintrin.h>
172  #elif defined (__SSE3__)
173  #include <pmmintrin.h>
174  #else
175  #include <emmintrin.h>
176  #endif
177  #endif //BT_USE_SSE
178  #elif defined( __armv7__ )
179  #ifdef __clang__
180  #define BT_USE_NEON 1
181 
182  #if defined BT_USE_NEON && defined (__clang__)
183  #include <arm_neon.h>
184  #endif//BT_USE_NEON
185  #endif //__clang__
186  #endif//__arm__
187 
188  #define SIMD_FORCE_INLINE inline __attribute__ ((always_inline))
189  #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16)))
191  #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64)))
192  #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128)))
193  #ifndef assert
194  #include <assert.h>
195  #endif
196 
197  #if defined(DEBUG) || defined (_DEBUG)
198  #if defined (__i386__) || defined (__x86_64__)
199  #include <stdio.h>
200  #define btAssert(x)\
201  {\
202  if(!(x))\
203  {\
204  printf("Assert %s in line %d, file %s\n",#x, __LINE__, __FILE__);\
205  asm volatile ("int3");\
206  }\
207  }
208  #else//defined (__i386__) || defined (__x86_64__)
209  #define btAssert assert
210  #end//defined (__i386__) || defined (__x86_64__)
211  #endif
212  #else//defined(DEBUG) || defined (_DEBUG)
213  #define btAssert(x)
214  #endif//defined(DEBUG) || defined (_DEBUG)
215 
216  //btFullAssert is optional, slows down a lot
217  #define btFullAssert(x)
218  #define btLikely(_c) _c
219  #define btUnlikely(_c) _c
220 
221 #else
222 
223  #define SIMD_FORCE_INLINE inline
224  #define ATTRIBUTE_ALIGNED16(a) a
229  #define ATTRIBUTE_ALIGNED64(a) a
230  #define ATTRIBUTE_ALIGNED128(a) a
231  #ifndef assert
232  #include <assert.h>
233  #endif
234 
235 #if defined(DEBUG) || defined (_DEBUG)
236  #define btAssert assert
237 #else
238  #define btAssert(x)
239 #endif
240 
241  //btFullAssert is optional, slows down a lot
242  #define btFullAssert(x)
243  #define btLikely(_c) _c
244  #define btUnlikely(_c) _c
245 #endif //__APPLE__
246 
247 #endif // LIBSPE2
248 
249 #endif //__CELLOS_LV2__
250 #endif
251 
252 
254 #if defined(BT_USE_DOUBLE_PRECISION)
255 typedef double btScalar;
256 //this number could be bigger in double precision
257 #define BT_LARGE_FLOAT 1e30
258 #else
259 typedef float btScalar;
260 //keep BT_LARGE_FLOAT*BT_LARGE_FLOAT < FLT_MAX
261 #define BT_LARGE_FLOAT 1e18f
262 #endif
263 
264 #ifdef BT_USE_SSE
265 typedef __m128 btSimdFloat4;
266 #endif//BT_USE_SSE
267 
268 #if defined BT_USE_SSE_IN_API && defined (BT_USE_SSE)
269 #ifdef _WIN32
270 
271 #ifndef BT_NAN
272 static int btNanMask = 0x7F800001;
273 #define BT_NAN (*(float*)&btNanMask)
274 #endif
275 
276 #ifndef BT_INFINITY
277 static int btInfinityMask = 0x7F800000;
278 #define BT_INFINITY (*(float*)&btInfinityMask)
279 #endif
280 
281 inline __m128 operator + (const __m128 A, const __m128 B)
282 {
283  return _mm_add_ps(A, B);
284 }
285 
286 inline __m128 operator - (const __m128 A, const __m128 B)
287 {
288  return _mm_sub_ps(A, B);
289 }
290 
291 inline __m128 operator * (const __m128 A, const __m128 B)
292 {
293  return _mm_mul_ps(A, B);
294 }
295 
296 #define btCastfTo128i(a) (_mm_castps_si128(a))
297 #define btCastfTo128d(a) (_mm_castps_pd(a))
298 #define btCastiTo128f(a) (_mm_castsi128_ps(a))
299 #define btCastdTo128f(a) (_mm_castpd_ps(a))
300 #define btCastdTo128i(a) (_mm_castpd_si128(a))
301 #define btAssign128(r0,r1,r2,r3) _mm_setr_ps(r0,r1,r2,r3)
302 
303 #else//_WIN32
304 
305 #define btCastfTo128i(a) ((__m128i)(a))
306 #define btCastfTo128d(a) ((__m128d)(a))
307 #define btCastiTo128f(a) ((__m128) (a))
308 #define btCastdTo128f(a) ((__m128) (a))
309 #define btCastdTo128i(a) ((__m128i)(a))
310 #define btAssign128(r0,r1,r2,r3) (__m128){r0,r1,r2,r3}
311 #define BT_INFINITY INFINITY
312 #define BT_NAN NAN
313 #endif//_WIN32
314 #endif //BT_USE_SSE_IN_API
315 
316 #ifdef BT_USE_NEON
317 #include <arm_neon.h>
318 
319 typedef float32x4_t btSimdFloat4;
320 #define BT_INFINITY INFINITY
321 #define BT_NAN NAN
322 #define btAssign128(r0,r1,r2,r3) (float32x4_t){r0,r1,r2,r3}
323 #endif
324 
325 
326 
327 
328 
329 #define BT_DECLARE_ALIGNED_ALLOCATOR() \
330  SIMD_FORCE_INLINE void* operator new(size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes,16); } \
331  SIMD_FORCE_INLINE void operator delete(void* ptr) { btAlignedFree(ptr); } \
332  SIMD_FORCE_INLINE void* operator new(size_t, void* ptr) { return ptr; } \
333  SIMD_FORCE_INLINE void operator delete(void*, void*) { } \
334  SIMD_FORCE_INLINE void* operator new[](size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes,16); } \
335  SIMD_FORCE_INLINE void operator delete[](void* ptr) { btAlignedFree(ptr); } \
336  SIMD_FORCE_INLINE void* operator new[](size_t, void* ptr) { return ptr; } \
337  SIMD_FORCE_INLINE void operator delete[](void*, void*) { } \
338 
339 
340 
341 #if defined(BT_USE_DOUBLE_PRECISION) || defined(BT_FORCE_DOUBLE_FUNCTIONS)
342 
343 SIMD_FORCE_INLINE btScalar btSqrt(btScalar x) { return sqrt(x); }
345 SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cos(x); }
346 SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sin(x); }
347 SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tan(x); }
348 SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { if (x<btScalar(-1)) x=btScalar(-1); if (x>btScalar(1)) x=btScalar(1); return acos(x); }
349 SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { if (x<btScalar(-1)) x=btScalar(-1); if (x>btScalar(1)) x=btScalar(1); return asin(x); }
350 SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atan(x); }
351 SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2(x, y); }
352 SIMD_FORCE_INLINE btScalar btExp(btScalar x) { return exp(x); }
353 SIMD_FORCE_INLINE btScalar btLog(btScalar x) { return log(x); }
354 SIMD_FORCE_INLINE btScalar btPow(btScalar x,btScalar y) { return pow(x,y); }
355 SIMD_FORCE_INLINE btScalar btFmod(btScalar x,btScalar y) { return fmod(x,y); }
356 
357 #else
358 
360 {
361 #ifdef USE_APPROXIMATION
362  double x, z, tempf;
363  unsigned long *tfptr = ((unsigned long *)&tempf) + 1;
364 
365  tempf = y;
366  *tfptr = (0xbfcdd90a - *tfptr)>>1; /* estimate of 1/sqrt(y) */
367  x = tempf;
368  z = y*btScalar(0.5);
369  x = (btScalar(1.5)*x)-(x*x)*(x*z); /* iteration formula */
370  x = (btScalar(1.5)*x)-(x*x)*(x*z);
371  x = (btScalar(1.5)*x)-(x*x)*(x*z);
372  x = (btScalar(1.5)*x)-(x*x)*(x*z);
373  x = (btScalar(1.5)*x)-(x*x)*(x*z);
374  return x*y;
375 #else
376  return sqrtf(y);
377 #endif
378 }
379 SIMD_FORCE_INLINE btScalar btFabs(btScalar x) { return fabsf(x); }
380 SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cosf(x); }
381 SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sinf(x); }
382 SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tanf(x); }
384  if (x<btScalar(-1))
385  x=btScalar(-1);
386  if (x>btScalar(1))
387  x=btScalar(1);
388  return acosf(x);
389 }
391  if (x<btScalar(-1))
392  x=btScalar(-1);
393  if (x>btScalar(1))
394  x=btScalar(1);
395  return asinf(x);
396 }
397 SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atanf(x); }
398 SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2f(x, y); }
399 SIMD_FORCE_INLINE btScalar btExp(btScalar x) { return expf(x); }
400 SIMD_FORCE_INLINE btScalar btLog(btScalar x) { return logf(x); }
402 SIMD_FORCE_INLINE btScalar btFmod(btScalar x,btScalar y) { return fmodf(x,y); }
403 
404 #endif
405 
406 #define SIMD_2_PI btScalar(6.283185307179586232)
407 #define SIMD_PI (SIMD_2_PI * btScalar(0.5))
408 #define SIMD_HALF_PI (SIMD_2_PI * btScalar(0.25))
409 #define SIMD_RADS_PER_DEG (SIMD_2_PI / btScalar(360.0))
410 #define SIMD_DEGS_PER_RAD (btScalar(360.0) / SIMD_2_PI)
411 #define SIMDSQRT12 btScalar(0.7071067811865475244008443621048490)
412 
413 #define btRecipSqrt(x) ((btScalar)(btScalar(1.0)/btSqrt(btScalar(x)))) /* reciprocal square root */
414 
415 
416 #ifdef BT_USE_DOUBLE_PRECISION
417 #define SIMD_EPSILON DBL_EPSILON
418 #define SIMD_INFINITY DBL_MAX
419 #else
420 #define SIMD_EPSILON FLT_EPSILON
421 #define SIMD_INFINITY FLT_MAX
422 #endif
423 
425 {
426  btScalar coeff_1 = SIMD_PI / 4.0f;
427  btScalar coeff_2 = 3.0f * coeff_1;
428  btScalar abs_y = btFabs(y);
429  btScalar angle;
430  if (x >= 0.0f) {
431  btScalar r = (x - abs_y) / (x + abs_y);
432  angle = coeff_1 - coeff_1 * r;
433  } else {
434  btScalar r = (x + abs_y) / (abs_y - x);
435  angle = coeff_2 - coeff_1 * r;
436  }
437  return (y < 0.0f) ? -angle : angle;
438 }
439 
441 
443  return (((a) <= eps) && !((a) < -eps));
444 }
446  return (!((a) <= eps));
447 }
448 
449 
451  return x < btScalar(0.0) ? 1 : 0;
452 }
453 
456 
457 #define BT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
458 
459 #ifndef btFsel
461 {
462  return a >= 0 ? b : c;
463 }
464 #endif
465 #define btFsels(a,b,c) (btScalar)btFsel(a,b,c)
466 
467 
469 {
470  long int i = 1;
471  const char *p = (const char *) &i;
472  if (p[0] == 1) // Lowest address contains the least significant byte
473  return true;
474  else
475  return false;
476 }
477 
478 
479 
482 SIMD_FORCE_INLINE unsigned btSelect(unsigned condition, unsigned valueIfConditionNonZero, unsigned valueIfConditionZero)
483 {
484  // Set testNz to 0xFFFFFFFF if condition is nonzero, 0x00000000 if condition is zero
485  // Rely on positive value or'ed with its negative having sign bit on
486  // and zero value or'ed with its negative (which is still zero) having sign bit off
487  // Use arithmetic shift right, shifting the sign bit through all 32 bits
488  unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31);
489  unsigned testEqz = ~testNz;
490  return ((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz));
491 }
492 SIMD_FORCE_INLINE int btSelect(unsigned condition, int valueIfConditionNonZero, int valueIfConditionZero)
493 {
494  unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31);
495  unsigned testEqz = ~testNz;
496  return static_cast<int>((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz));
497 }
498 SIMD_FORCE_INLINE float btSelect(unsigned condition, float valueIfConditionNonZero, float valueIfConditionZero)
499 {
500 #ifdef BT_HAVE_NATIVE_FSEL
501  return (float)btFsel((btScalar)condition - btScalar(1.0f), valueIfConditionNonZero, valueIfConditionZero);
502 #else
503  return (condition != 0) ? valueIfConditionNonZero : valueIfConditionZero;
504 #endif
505 }
506 
507 template<typename T> SIMD_FORCE_INLINE void btSwap(T& a, T& b)
508 {
509  T tmp = a;
510  a = b;
511  b = tmp;
512 }
513 
514 
515 //PCK: endian swapping functions
516 SIMD_FORCE_INLINE unsigned btSwapEndian(unsigned val)
517 {
518  return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24));
519 }
520 
521 SIMD_FORCE_INLINE unsigned short btSwapEndian(unsigned short val)
522 {
523  return static_cast<unsigned short>(((val & 0xff00) >> 8) | ((val & 0x00ff) << 8));
524 }
525 
527 {
528  return btSwapEndian((unsigned)val);
529 }
530 
531 SIMD_FORCE_INLINE unsigned short btSwapEndian(short val)
532 {
533  return btSwapEndian((unsigned short) val);
534 }
535 
543 {
544  unsigned int a = 0;
545  unsigned char *dst = (unsigned char *)&a;
546  unsigned char *src = (unsigned char *)&d;
547 
548  dst[0] = src[3];
549  dst[1] = src[2];
550  dst[2] = src[1];
551  dst[3] = src[0];
552  return a;
553 }
554 
555 // unswap using char pointers
557 {
558  float d = 0.0f;
559  unsigned char *src = (unsigned char *)&a;
560  unsigned char *dst = (unsigned char *)&d;
561 
562  dst[0] = src[3];
563  dst[1] = src[2];
564  dst[2] = src[1];
565  dst[3] = src[0];
566 
567  return d;
568 }
569 
570 
571 // swap using char pointers
572 SIMD_FORCE_INLINE void btSwapEndianDouble(double d, unsigned char* dst)
573 {
574  unsigned char *src = (unsigned char *)&d;
575 
576  dst[0] = src[7];
577  dst[1] = src[6];
578  dst[2] = src[5];
579  dst[3] = src[4];
580  dst[4] = src[3];
581  dst[5] = src[2];
582  dst[6] = src[1];
583  dst[7] = src[0];
584 
585 }
586 
587 // unswap using char pointers
588 SIMD_FORCE_INLINE double btUnswapEndianDouble(const unsigned char *src)
589 {
590  double d = 0.0;
591  unsigned char *dst = (unsigned char *)&d;
592 
593  dst[0] = src[7];
594  dst[1] = src[6];
595  dst[2] = src[5];
596  dst[3] = src[4];
597  dst[4] = src[3];
598  dst[5] = src[2];
599  dst[6] = src[1];
600  dst[7] = src[0];
601 
602  return d;
603 }
604 
605 // returns normalized value in range [-SIMD_PI, SIMD_PI]
607 {
608  angleInRadians = btFmod(angleInRadians, SIMD_2_PI);
609  if(angleInRadians < -SIMD_PI)
610  {
611  return angleInRadians + SIMD_2_PI;
612  }
613  else if(angleInRadians > SIMD_PI)
614  {
615  return angleInRadians - SIMD_2_PI;
616  }
617  else
618  {
619  return angleInRadians;
620  }
621 }
622 
625 {
626  btTypedObject(int objectType)
627  :m_objectType(objectType)
628  {
629  }
631  inline int getObjectType() const
632  {
633  return m_objectType;
634  }
635 };
636 
637 
638 
640 template <typename T>T* btAlignPointer(T* unalignedPtr, size_t alignment)
641 {
642 
643  struct btConvertPointerSizeT
644  {
645  union
646  {
647  T* ptr;
648  size_t integer;
649  };
650  };
651  btConvertPointerSizeT converter;
652 
653 
654  const size_t bit_mask = ~(alignment - 1);
655  converter.ptr = unalignedPtr;
656  converter.integer += alignment-1;
657  converter.integer &= bit_mask;
658  return converter.ptr;
659 }
660 
661 #endif //BT_SCALAR_H