macros.h revision 848b8605
1848b8605Smrg/** 2848b8605Smrg * \file macros.h 3848b8605Smrg * A collection of useful macros. 4848b8605Smrg */ 5848b8605Smrg 6848b8605Smrg/* 7848b8605Smrg * Mesa 3-D graphics library 8848b8605Smrg * 9848b8605Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 10848b8605Smrg * 11848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 12848b8605Smrg * copy of this software and associated documentation files (the "Software"), 13848b8605Smrg * to deal in the Software without restriction, including without limitation 14848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 16848b8605Smrg * Software is furnished to do so, subject to the following conditions: 17848b8605Smrg * 18848b8605Smrg * The above copyright notice and this permission notice shall be included 19848b8605Smrg * in all copies or substantial portions of the Software. 20848b8605Smrg * 21848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 28848b8605Smrg */ 29848b8605Smrg 30848b8605Smrg 31848b8605Smrg#ifndef MACROS_H 32848b8605Smrg#define MACROS_H 33848b8605Smrg 34848b8605Smrg#include "imports.h" 35848b8605Smrg 36848b8605Smrg 37848b8605Smrg/** 38848b8605Smrg * \name Integer / float conversion for colors, normals, etc. 39848b8605Smrg */ 40848b8605Smrg/*@{*/ 41848b8605Smrg 42848b8605Smrg/** Convert GLubyte in [0,255] to GLfloat in [0.0,1.0] */ 43848b8605Smrgextern GLfloat _mesa_ubyte_to_float_color_tab[256]; 44848b8605Smrg#define UBYTE_TO_FLOAT(u) _mesa_ubyte_to_float_color_tab[(unsigned int)(u)] 45848b8605Smrg 46848b8605Smrg/** Convert GLfloat in [0.0,1.0] to GLubyte in [0,255] */ 47848b8605Smrg#define FLOAT_TO_UBYTE(X) ((GLubyte) (GLint) ((X) * 255.0F)) 48848b8605Smrg 49848b8605Smrg 50848b8605Smrg/** Convert GLbyte in [-128,127] to GLfloat in [-1.0,1.0] */ 51848b8605Smrg#define BYTE_TO_FLOAT(B) ((2.0F * (B) + 1.0F) * (1.0F/255.0F)) 52848b8605Smrg 53848b8605Smrg/** Convert GLfloat in [-1.0,1.0] to GLbyte in [-128,127] */ 54848b8605Smrg#define FLOAT_TO_BYTE(X) ( (((GLint) (255.0F * (X))) - 1) / 2 ) 55848b8605Smrg 56848b8605Smrg 57848b8605Smrg/** Convert GLbyte to GLfloat while preserving zero */ 58848b8605Smrg#define BYTE_TO_FLOATZ(B) ((B) == 0 ? 0.0F : BYTE_TO_FLOAT(B)) 59848b8605Smrg 60848b8605Smrg 61848b8605Smrg/** Convert GLbyte in [-128,127] to GLfloat in [-1.0,1.0], texture/fb data */ 62848b8605Smrg#define BYTE_TO_FLOAT_TEX(B) ((B) == -128 ? -1.0F : (B) * (1.0F/127.0F)) 63848b8605Smrg 64848b8605Smrg/** Convert GLfloat in [-1.0,1.0] to GLbyte in [-128,127], texture/fb data */ 65848b8605Smrg#define FLOAT_TO_BYTE_TEX(X) CLAMP( (GLint) (127.0F * (X)), -128, 127 ) 66848b8605Smrg 67848b8605Smrg/** Convert GLushort in [0,65535] to GLfloat in [0.0,1.0] */ 68848b8605Smrg#define USHORT_TO_FLOAT(S) ((GLfloat) (S) * (1.0F / 65535.0F)) 69848b8605Smrg 70848b8605Smrg/** Convert GLfloat in [0.0,1.0] to GLushort in [0, 65535] */ 71848b8605Smrg#define FLOAT_TO_USHORT(X) ((GLuint) ((X) * 65535.0F)) 72848b8605Smrg 73848b8605Smrg 74848b8605Smrg/** Convert GLshort in [-32768,32767] to GLfloat in [-1.0,1.0] */ 75848b8605Smrg#define SHORT_TO_FLOAT(S) ((2.0F * (S) + 1.0F) * (1.0F/65535.0F)) 76848b8605Smrg 77848b8605Smrg/** Convert GLfloat in [-1.0,1.0] to GLshort in [-32768,32767] */ 78848b8605Smrg#define FLOAT_TO_SHORT(X) ( (((GLint) (65535.0F * (X))) - 1) / 2 ) 79848b8605Smrg 80848b8605Smrg/** Convert GLshort to GLfloat while preserving zero */ 81848b8605Smrg#define SHORT_TO_FLOATZ(S) ((S) == 0 ? 0.0F : SHORT_TO_FLOAT(S)) 82848b8605Smrg 83848b8605Smrg 84848b8605Smrg/** Convert GLshort in [-32768,32767] to GLfloat in [-1.0,1.0], texture/fb data */ 85848b8605Smrg#define SHORT_TO_FLOAT_TEX(S) ((S) == -32768 ? -1.0F : (S) * (1.0F/32767.0F)) 86848b8605Smrg 87848b8605Smrg/** Convert GLfloat in [-1.0,1.0] to GLshort in [-32768,32767], texture/fb data */ 88848b8605Smrg#define FLOAT_TO_SHORT_TEX(X) ( (GLint) (32767.0F * (X)) ) 89848b8605Smrg 90848b8605Smrg 91848b8605Smrg/** Convert GLuint in [0,4294967295] to GLfloat in [0.0,1.0] */ 92848b8605Smrg#define UINT_TO_FLOAT(U) ((GLfloat) ((U) * (1.0F / 4294967295.0))) 93848b8605Smrg 94848b8605Smrg/** Convert GLfloat in [0.0,1.0] to GLuint in [0,4294967295] */ 95848b8605Smrg#define FLOAT_TO_UINT(X) ((GLuint) ((X) * 4294967295.0)) 96848b8605Smrg 97848b8605Smrg 98848b8605Smrg/** Convert GLint in [-2147483648,2147483647] to GLfloat in [-1.0,1.0] */ 99848b8605Smrg#define INT_TO_FLOAT(I) ((GLfloat) ((2.0F * (I) + 1.0F) * (1.0F/4294967294.0))) 100848b8605Smrg 101848b8605Smrg/** Convert GLfloat in [-1.0,1.0] to GLint in [-2147483648,2147483647] */ 102848b8605Smrg/* causes overflow: 103848b8605Smrg#define FLOAT_TO_INT(X) ( (((GLint) (4294967294.0 * (X))) - 1) / 2 ) 104848b8605Smrg*/ 105848b8605Smrg/* a close approximation: */ 106848b8605Smrg#define FLOAT_TO_INT(X) ( (GLint) (2147483647.0 * (X)) ) 107848b8605Smrg 108848b8605Smrg/** Convert GLfloat in [-1.0,1.0] to GLint64 in [-(1<<63),(1 << 63) -1] */ 109848b8605Smrg#define FLOAT_TO_INT64(X) ( (GLint64) (9223372036854775807.0 * (double)(X)) ) 110848b8605Smrg 111848b8605Smrg 112848b8605Smrg/** Convert GLint in [-2147483648,2147483647] to GLfloat in [-1.0,1.0], texture/fb data */ 113848b8605Smrg#define INT_TO_FLOAT_TEX(I) ((I) == -2147483648 ? -1.0F : (I) * (1.0F/2147483647.0)) 114848b8605Smrg 115848b8605Smrg/** Convert GLfloat in [-1.0,1.0] to GLint in [-2147483648,2147483647], texture/fb data */ 116848b8605Smrg#define FLOAT_TO_INT_TEX(X) ( (GLint) (2147483647.0 * (X)) ) 117848b8605Smrg 118848b8605Smrg 119848b8605Smrg#define BYTE_TO_UBYTE(b) ((GLubyte) ((b) < 0 ? 0 : (GLubyte) (b))) 120848b8605Smrg#define SHORT_TO_UBYTE(s) ((GLubyte) ((s) < 0 ? 0 : (GLubyte) ((s) >> 7))) 121848b8605Smrg#define USHORT_TO_UBYTE(s) ((GLubyte) ((s) >> 8)) 122848b8605Smrg#define INT_TO_UBYTE(i) ((GLubyte) ((i) < 0 ? 0 : (GLubyte) ((i) >> 23))) 123848b8605Smrg#define UINT_TO_UBYTE(i) ((GLubyte) ((i) >> 24)) 124848b8605Smrg 125848b8605Smrg 126848b8605Smrg#define BYTE_TO_USHORT(b) ((b) < 0 ? 0 : ((GLushort) (((b) * 65535) / 255))) 127848b8605Smrg#define UBYTE_TO_USHORT(b) (((GLushort) (b) << 8) | (GLushort) (b)) 128848b8605Smrg#define SHORT_TO_USHORT(s) ((s) < 0 ? 0 : ((GLushort) (((s) * 65535 / 32767)))) 129848b8605Smrg#define INT_TO_USHORT(i) ((i) < 0 ? 0 : ((GLushort) ((i) >> 15))) 130848b8605Smrg#define UINT_TO_USHORT(i) ((i) < 0 ? 0 : ((GLushort) ((i) >> 16))) 131848b8605Smrg#define UNCLAMPED_FLOAT_TO_USHORT(us, f) \ 132848b8605Smrg us = ( (GLushort) F_TO_I( CLAMP((f), 0.0F, 1.0F) * 65535.0F) ) 133848b8605Smrg#define CLAMPED_FLOAT_TO_USHORT(us, f) \ 134848b8605Smrg us = ( (GLushort) F_TO_I( (f) * 65535.0F) ) 135848b8605Smrg 136848b8605Smrg#define UNCLAMPED_FLOAT_TO_SHORT(s, f) \ 137848b8605Smrg s = ( (GLshort) F_TO_I( CLAMP((f), -1.0F, 1.0F) * 32767.0F) ) 138848b8605Smrg 139848b8605Smrg/*** 140848b8605Smrg *** UNCLAMPED_FLOAT_TO_UBYTE: clamp float to [0,1] and map to ubyte in [0,255] 141848b8605Smrg *** CLAMPED_FLOAT_TO_UBYTE: map float known to be in [0,1] to ubyte in [0,255] 142848b8605Smrg ***/ 143848b8605Smrg#ifndef DEBUG 144848b8605Smrg/* This function/macro is sensitive to precision. Test very carefully 145848b8605Smrg * if you change it! 146848b8605Smrg */ 147848b8605Smrg#define UNCLAMPED_FLOAT_TO_UBYTE(UB, FLT) \ 148848b8605Smrg do { \ 149848b8605Smrg fi_type __tmp; \ 150848b8605Smrg __tmp.f = (FLT); \ 151848b8605Smrg if (__tmp.i < 0) \ 152848b8605Smrg UB = (GLubyte) 0; \ 153848b8605Smrg else if (__tmp.i >= IEEE_ONE) \ 154848b8605Smrg UB = (GLubyte) 255; \ 155848b8605Smrg else { \ 156848b8605Smrg __tmp.f = __tmp.f * (255.0F/256.0F) + 32768.0F; \ 157848b8605Smrg UB = (GLubyte) __tmp.i; \ 158848b8605Smrg } \ 159848b8605Smrg } while (0) 160848b8605Smrg#define CLAMPED_FLOAT_TO_UBYTE(UB, FLT) \ 161848b8605Smrg do { \ 162848b8605Smrg fi_type __tmp; \ 163848b8605Smrg __tmp.f = (FLT) * (255.0F/256.0F) + 32768.0F; \ 164848b8605Smrg UB = (GLubyte) __tmp.i; \ 165848b8605Smrg } while (0) 166848b8605Smrg#else 167848b8605Smrg#define UNCLAMPED_FLOAT_TO_UBYTE(ub, f) \ 168848b8605Smrg ub = ((GLubyte) F_TO_I(CLAMP((f), 0.0F, 1.0F) * 255.0F)) 169848b8605Smrg#define CLAMPED_FLOAT_TO_UBYTE(ub, f) \ 170848b8605Smrg ub = ((GLubyte) F_TO_I((f) * 255.0F)) 171848b8605Smrg#endif 172848b8605Smrg 173848b8605Smrgstatic inline GLfloat INT_AS_FLT(GLint i) 174848b8605Smrg{ 175848b8605Smrg fi_type tmp; 176848b8605Smrg tmp.i = i; 177848b8605Smrg return tmp.f; 178848b8605Smrg} 179848b8605Smrg 180848b8605Smrgstatic inline GLfloat UINT_AS_FLT(GLuint u) 181848b8605Smrg{ 182848b8605Smrg fi_type tmp; 183848b8605Smrg tmp.u = u; 184848b8605Smrg return tmp.f; 185848b8605Smrg} 186848b8605Smrg 187848b8605Smrgstatic inline unsigned FLT_AS_UINT(float f) 188848b8605Smrg{ 189848b8605Smrg fi_type tmp; 190848b8605Smrg tmp.f = f; 191848b8605Smrg return tmp.u; 192848b8605Smrg} 193848b8605Smrg 194848b8605Smrg/** 195848b8605Smrg * Convert a floating point value to an unsigned fixed point value. 196848b8605Smrg * 197848b8605Smrg * \param frac_bits The number of bits used to store the fractional part. 198848b8605Smrg */ 199848b8605Smrgstatic INLINE uint32_t 200848b8605SmrgU_FIXED(float value, uint32_t frac_bits) 201848b8605Smrg{ 202848b8605Smrg value *= (1 << frac_bits); 203848b8605Smrg return value < 0.0f ? 0 : (uint32_t) value; 204848b8605Smrg} 205848b8605Smrg 206848b8605Smrg/** 207848b8605Smrg * Convert a floating point value to an signed fixed point value. 208848b8605Smrg * 209848b8605Smrg * \param frac_bits The number of bits used to store the fractional part. 210848b8605Smrg */ 211848b8605Smrgstatic INLINE int32_t 212848b8605SmrgS_FIXED(float value, uint32_t frac_bits) 213848b8605Smrg{ 214848b8605Smrg return (int32_t) (value * (1 << frac_bits)); 215848b8605Smrg} 216848b8605Smrg/*@}*/ 217848b8605Smrg 218848b8605Smrg 219848b8605Smrg/** Stepping a GLfloat pointer by a byte stride */ 220848b8605Smrg#define STRIDE_F(p, i) (p = (GLfloat *)((GLubyte *)p + i)) 221848b8605Smrg/** Stepping a GLuint pointer by a byte stride */ 222848b8605Smrg#define STRIDE_UI(p, i) (p = (GLuint *)((GLubyte *)p + i)) 223848b8605Smrg/** Stepping a GLubyte[4] pointer by a byte stride */ 224848b8605Smrg#define STRIDE_4UB(p, i) (p = (GLubyte (*)[4])((GLubyte *)p + i)) 225848b8605Smrg/** Stepping a GLfloat[4] pointer by a byte stride */ 226848b8605Smrg#define STRIDE_4F(p, i) (p = (GLfloat (*)[4])((GLubyte *)p + i)) 227848b8605Smrg/** Stepping a \p t pointer by a byte stride */ 228848b8605Smrg#define STRIDE_T(p, t, i) (p = (t)((GLubyte *)p + i)) 229848b8605Smrg 230848b8605Smrg 231848b8605Smrg/**********************************************************************/ 232848b8605Smrg/** \name 4-element vector operations */ 233848b8605Smrg/*@{*/ 234848b8605Smrg 235848b8605Smrg/** Zero */ 236848b8605Smrg#define ZERO_4V( DST ) (DST)[0] = (DST)[1] = (DST)[2] = (DST)[3] = 0 237848b8605Smrg 238848b8605Smrg/** Test for equality */ 239848b8605Smrg#define TEST_EQ_4V(a,b) ((a)[0] == (b)[0] && \ 240848b8605Smrg (a)[1] == (b)[1] && \ 241848b8605Smrg (a)[2] == (b)[2] && \ 242848b8605Smrg (a)[3] == (b)[3]) 243848b8605Smrg 244848b8605Smrg/** Test for equality (unsigned bytes) */ 245848b8605Smrgstatic inline GLboolean 246848b8605SmrgTEST_EQ_4UBV(const GLubyte a[4], const GLubyte b[4]) 247848b8605Smrg{ 248848b8605Smrg#if defined(__i386__) 249848b8605Smrg return *((const GLuint *) a) == *((const GLuint *) b); 250848b8605Smrg#else 251848b8605Smrg return TEST_EQ_4V(a, b); 252848b8605Smrg#endif 253848b8605Smrg} 254848b8605Smrg 255848b8605Smrg 256848b8605Smrg/** Copy a 4-element vector */ 257848b8605Smrg#define COPY_4V( DST, SRC ) \ 258848b8605Smrgdo { \ 259848b8605Smrg (DST)[0] = (SRC)[0]; \ 260848b8605Smrg (DST)[1] = (SRC)[1]; \ 261848b8605Smrg (DST)[2] = (SRC)[2]; \ 262848b8605Smrg (DST)[3] = (SRC)[3]; \ 263848b8605Smrg} while (0) 264848b8605Smrg 265848b8605Smrg/** Copy a 4-element unsigned byte vector */ 266848b8605Smrgstatic inline void 267848b8605SmrgCOPY_4UBV(GLubyte dst[4], const GLubyte src[4]) 268848b8605Smrg{ 269848b8605Smrg#if defined(__i386__) 270848b8605Smrg *((GLuint *) dst) = *((GLuint *) src); 271848b8605Smrg#else 272848b8605Smrg /* The GLuint cast might fail if DST or SRC are not dword-aligned (RISC) */ 273848b8605Smrg COPY_4V(dst, src); 274848b8605Smrg#endif 275848b8605Smrg} 276848b8605Smrg 277848b8605Smrg/** Copy a 4-element float vector */ 278848b8605Smrgstatic inline void 279848b8605SmrgCOPY_4FV(GLfloat dst[4], const GLfloat src[4]) 280848b8605Smrg{ 281848b8605Smrg /* memcpy seems to be most efficient */ 282848b8605Smrg memcpy(dst, src, sizeof(GLfloat) * 4); 283848b8605Smrg} 284848b8605Smrg 285848b8605Smrg/** Copy \p SZ elements into a 4-element vector */ 286848b8605Smrg#define COPY_SZ_4V(DST, SZ, SRC) \ 287848b8605Smrgdo { \ 288848b8605Smrg switch (SZ) { \ 289848b8605Smrg case 4: (DST)[3] = (SRC)[3]; \ 290848b8605Smrg case 3: (DST)[2] = (SRC)[2]; \ 291848b8605Smrg case 2: (DST)[1] = (SRC)[1]; \ 292848b8605Smrg case 1: (DST)[0] = (SRC)[0]; \ 293848b8605Smrg } \ 294848b8605Smrg} while(0) 295848b8605Smrg 296848b8605Smrg/** Copy \p SZ elements into a homegeneous (4-element) vector, giving 297848b8605Smrg * default values to the remaining */ 298848b8605Smrg#define COPY_CLEAN_4V(DST, SZ, SRC) \ 299848b8605Smrgdo { \ 300848b8605Smrg ASSIGN_4V( DST, 0, 0, 0, 1 ); \ 301848b8605Smrg COPY_SZ_4V( DST, SZ, SRC ); \ 302848b8605Smrg} while (0) 303848b8605Smrg 304848b8605Smrg/** Subtraction */ 305848b8605Smrg#define SUB_4V( DST, SRCA, SRCB ) \ 306848b8605Smrgdo { \ 307848b8605Smrg (DST)[0] = (SRCA)[0] - (SRCB)[0]; \ 308848b8605Smrg (DST)[1] = (SRCA)[1] - (SRCB)[1]; \ 309848b8605Smrg (DST)[2] = (SRCA)[2] - (SRCB)[2]; \ 310848b8605Smrg (DST)[3] = (SRCA)[3] - (SRCB)[3]; \ 311848b8605Smrg} while (0) 312848b8605Smrg 313848b8605Smrg/** Addition */ 314848b8605Smrg#define ADD_4V( DST, SRCA, SRCB ) \ 315848b8605Smrgdo { \ 316848b8605Smrg (DST)[0] = (SRCA)[0] + (SRCB)[0]; \ 317848b8605Smrg (DST)[1] = (SRCA)[1] + (SRCB)[1]; \ 318848b8605Smrg (DST)[2] = (SRCA)[2] + (SRCB)[2]; \ 319848b8605Smrg (DST)[3] = (SRCA)[3] + (SRCB)[3]; \ 320848b8605Smrg} while (0) 321848b8605Smrg 322848b8605Smrg/** Element-wise multiplication */ 323848b8605Smrg#define SCALE_4V( DST, SRCA, SRCB ) \ 324848b8605Smrgdo { \ 325848b8605Smrg (DST)[0] = (SRCA)[0] * (SRCB)[0]; \ 326848b8605Smrg (DST)[1] = (SRCA)[1] * (SRCB)[1]; \ 327848b8605Smrg (DST)[2] = (SRCA)[2] * (SRCB)[2]; \ 328848b8605Smrg (DST)[3] = (SRCA)[3] * (SRCB)[3]; \ 329848b8605Smrg} while (0) 330848b8605Smrg 331848b8605Smrg/** In-place addition */ 332848b8605Smrg#define ACC_4V( DST, SRC ) \ 333848b8605Smrgdo { \ 334848b8605Smrg (DST)[0] += (SRC)[0]; \ 335848b8605Smrg (DST)[1] += (SRC)[1]; \ 336848b8605Smrg (DST)[2] += (SRC)[2]; \ 337848b8605Smrg (DST)[3] += (SRC)[3]; \ 338848b8605Smrg} while (0) 339848b8605Smrg 340848b8605Smrg/** Element-wise multiplication and addition */ 341848b8605Smrg#define ACC_SCALE_4V( DST, SRCA, SRCB ) \ 342848b8605Smrgdo { \ 343848b8605Smrg (DST)[0] += (SRCA)[0] * (SRCB)[0]; \ 344848b8605Smrg (DST)[1] += (SRCA)[1] * (SRCB)[1]; \ 345848b8605Smrg (DST)[2] += (SRCA)[2] * (SRCB)[2]; \ 346848b8605Smrg (DST)[3] += (SRCA)[3] * (SRCB)[3]; \ 347848b8605Smrg} while (0) 348848b8605Smrg 349848b8605Smrg/** In-place scalar multiplication and addition */ 350848b8605Smrg#define ACC_SCALE_SCALAR_4V( DST, S, SRCB ) \ 351848b8605Smrgdo { \ 352848b8605Smrg (DST)[0] += S * (SRCB)[0]; \ 353848b8605Smrg (DST)[1] += S * (SRCB)[1]; \ 354848b8605Smrg (DST)[2] += S * (SRCB)[2]; \ 355848b8605Smrg (DST)[3] += S * (SRCB)[3]; \ 356848b8605Smrg} while (0) 357848b8605Smrg 358848b8605Smrg/** Scalar multiplication */ 359848b8605Smrg#define SCALE_SCALAR_4V( DST, S, SRCB ) \ 360848b8605Smrgdo { \ 361848b8605Smrg (DST)[0] = S * (SRCB)[0]; \ 362848b8605Smrg (DST)[1] = S * (SRCB)[1]; \ 363848b8605Smrg (DST)[2] = S * (SRCB)[2]; \ 364848b8605Smrg (DST)[3] = S * (SRCB)[3]; \ 365848b8605Smrg} while (0) 366848b8605Smrg 367848b8605Smrg/** In-place scalar multiplication */ 368848b8605Smrg#define SELF_SCALE_SCALAR_4V( DST, S ) \ 369848b8605Smrgdo { \ 370848b8605Smrg (DST)[0] *= S; \ 371848b8605Smrg (DST)[1] *= S; \ 372848b8605Smrg (DST)[2] *= S; \ 373848b8605Smrg (DST)[3] *= S; \ 374848b8605Smrg} while (0) 375848b8605Smrg 376848b8605Smrg/** Assignment */ 377848b8605Smrg#define ASSIGN_4V( V, V0, V1, V2, V3 ) \ 378848b8605Smrgdo { \ 379848b8605Smrg V[0] = V0; \ 380848b8605Smrg V[1] = V1; \ 381848b8605Smrg V[2] = V2; \ 382848b8605Smrg V[3] = V3; \ 383848b8605Smrg} while(0) 384848b8605Smrg 385848b8605Smrg/*@}*/ 386848b8605Smrg 387848b8605Smrg 388848b8605Smrg/**********************************************************************/ 389848b8605Smrg/** \name 3-element vector operations*/ 390848b8605Smrg/*@{*/ 391848b8605Smrg 392848b8605Smrg/** Zero */ 393848b8605Smrg#define ZERO_3V( DST ) (DST)[0] = (DST)[1] = (DST)[2] = 0 394848b8605Smrg 395848b8605Smrg/** Test for equality */ 396848b8605Smrg#define TEST_EQ_3V(a,b) \ 397848b8605Smrg ((a)[0] == (b)[0] && \ 398848b8605Smrg (a)[1] == (b)[1] && \ 399848b8605Smrg (a)[2] == (b)[2]) 400848b8605Smrg 401848b8605Smrg/** Copy a 3-element vector */ 402848b8605Smrg#define COPY_3V( DST, SRC ) \ 403848b8605Smrgdo { \ 404848b8605Smrg (DST)[0] = (SRC)[0]; \ 405848b8605Smrg (DST)[1] = (SRC)[1]; \ 406848b8605Smrg (DST)[2] = (SRC)[2]; \ 407848b8605Smrg} while (0) 408848b8605Smrg 409848b8605Smrg/** Copy a 3-element vector with cast */ 410848b8605Smrg#define COPY_3V_CAST( DST, SRC, CAST ) \ 411848b8605Smrgdo { \ 412848b8605Smrg (DST)[0] = (CAST)(SRC)[0]; \ 413848b8605Smrg (DST)[1] = (CAST)(SRC)[1]; \ 414848b8605Smrg (DST)[2] = (CAST)(SRC)[2]; \ 415848b8605Smrg} while (0) 416848b8605Smrg 417848b8605Smrg/** Copy a 3-element float vector */ 418848b8605Smrg#define COPY_3FV( DST, SRC ) \ 419848b8605Smrgdo { \ 420848b8605Smrg const GLfloat *_tmp = (SRC); \ 421848b8605Smrg (DST)[0] = _tmp[0]; \ 422848b8605Smrg (DST)[1] = _tmp[1]; \ 423848b8605Smrg (DST)[2] = _tmp[2]; \ 424848b8605Smrg} while (0) 425848b8605Smrg 426848b8605Smrg/** Subtraction */ 427848b8605Smrg#define SUB_3V( DST, SRCA, SRCB ) \ 428848b8605Smrgdo { \ 429848b8605Smrg (DST)[0] = (SRCA)[0] - (SRCB)[0]; \ 430848b8605Smrg (DST)[1] = (SRCA)[1] - (SRCB)[1]; \ 431848b8605Smrg (DST)[2] = (SRCA)[2] - (SRCB)[2]; \ 432848b8605Smrg} while (0) 433848b8605Smrg 434848b8605Smrg/** Addition */ 435848b8605Smrg#define ADD_3V( DST, SRCA, SRCB ) \ 436848b8605Smrgdo { \ 437848b8605Smrg (DST)[0] = (SRCA)[0] + (SRCB)[0]; \ 438848b8605Smrg (DST)[1] = (SRCA)[1] + (SRCB)[1]; \ 439848b8605Smrg (DST)[2] = (SRCA)[2] + (SRCB)[2]; \ 440848b8605Smrg} while (0) 441848b8605Smrg 442848b8605Smrg/** In-place scalar multiplication */ 443848b8605Smrg#define SCALE_3V( DST, SRCA, SRCB ) \ 444848b8605Smrgdo { \ 445848b8605Smrg (DST)[0] = (SRCA)[0] * (SRCB)[0]; \ 446848b8605Smrg (DST)[1] = (SRCA)[1] * (SRCB)[1]; \ 447848b8605Smrg (DST)[2] = (SRCA)[2] * (SRCB)[2]; \ 448848b8605Smrg} while (0) 449848b8605Smrg 450848b8605Smrg/** In-place element-wise multiplication */ 451848b8605Smrg#define SELF_SCALE_3V( DST, SRC ) \ 452848b8605Smrgdo { \ 453848b8605Smrg (DST)[0] *= (SRC)[0]; \ 454848b8605Smrg (DST)[1] *= (SRC)[1]; \ 455848b8605Smrg (DST)[2] *= (SRC)[2]; \ 456848b8605Smrg} while (0) 457848b8605Smrg 458848b8605Smrg/** In-place addition */ 459848b8605Smrg#define ACC_3V( DST, SRC ) \ 460848b8605Smrgdo { \ 461848b8605Smrg (DST)[0] += (SRC)[0]; \ 462848b8605Smrg (DST)[1] += (SRC)[1]; \ 463848b8605Smrg (DST)[2] += (SRC)[2]; \ 464848b8605Smrg} while (0) 465848b8605Smrg 466848b8605Smrg/** Element-wise multiplication and addition */ 467848b8605Smrg#define ACC_SCALE_3V( DST, SRCA, SRCB ) \ 468848b8605Smrgdo { \ 469848b8605Smrg (DST)[0] += (SRCA)[0] * (SRCB)[0]; \ 470848b8605Smrg (DST)[1] += (SRCA)[1] * (SRCB)[1]; \ 471848b8605Smrg (DST)[2] += (SRCA)[2] * (SRCB)[2]; \ 472848b8605Smrg} while (0) 473848b8605Smrg 474848b8605Smrg/** Scalar multiplication */ 475848b8605Smrg#define SCALE_SCALAR_3V( DST, S, SRCB ) \ 476848b8605Smrgdo { \ 477848b8605Smrg (DST)[0] = S * (SRCB)[0]; \ 478848b8605Smrg (DST)[1] = S * (SRCB)[1]; \ 479848b8605Smrg (DST)[2] = S * (SRCB)[2]; \ 480848b8605Smrg} while (0) 481848b8605Smrg 482848b8605Smrg/** In-place scalar multiplication and addition */ 483848b8605Smrg#define ACC_SCALE_SCALAR_3V( DST, S, SRCB ) \ 484848b8605Smrgdo { \ 485848b8605Smrg (DST)[0] += S * (SRCB)[0]; \ 486848b8605Smrg (DST)[1] += S * (SRCB)[1]; \ 487848b8605Smrg (DST)[2] += S * (SRCB)[2]; \ 488848b8605Smrg} while (0) 489848b8605Smrg 490848b8605Smrg/** In-place scalar multiplication */ 491848b8605Smrg#define SELF_SCALE_SCALAR_3V( DST, S ) \ 492848b8605Smrgdo { \ 493848b8605Smrg (DST)[0] *= S; \ 494848b8605Smrg (DST)[1] *= S; \ 495848b8605Smrg (DST)[2] *= S; \ 496848b8605Smrg} while (0) 497848b8605Smrg 498848b8605Smrg/** In-place scalar addition */ 499848b8605Smrg#define ACC_SCALAR_3V( DST, S ) \ 500848b8605Smrgdo { \ 501848b8605Smrg (DST)[0] += S; \ 502848b8605Smrg (DST)[1] += S; \ 503848b8605Smrg (DST)[2] += S; \ 504848b8605Smrg} while (0) 505848b8605Smrg 506848b8605Smrg/** Assignment */ 507848b8605Smrg#define ASSIGN_3V( V, V0, V1, V2 ) \ 508848b8605Smrgdo { \ 509848b8605Smrg V[0] = V0; \ 510848b8605Smrg V[1] = V1; \ 511848b8605Smrg V[2] = V2; \ 512848b8605Smrg} while(0) 513848b8605Smrg 514848b8605Smrg/*@}*/ 515848b8605Smrg 516848b8605Smrg 517848b8605Smrg/**********************************************************************/ 518848b8605Smrg/** \name 2-element vector operations*/ 519848b8605Smrg/*@{*/ 520848b8605Smrg 521848b8605Smrg/** Zero */ 522848b8605Smrg#define ZERO_2V( DST ) (DST)[0] = (DST)[1] = 0 523848b8605Smrg 524848b8605Smrg/** Copy a 2-element vector */ 525848b8605Smrg#define COPY_2V( DST, SRC ) \ 526848b8605Smrgdo { \ 527848b8605Smrg (DST)[0] = (SRC)[0]; \ 528848b8605Smrg (DST)[1] = (SRC)[1]; \ 529848b8605Smrg} while (0) 530848b8605Smrg 531848b8605Smrg/** Copy a 2-element vector with cast */ 532848b8605Smrg#define COPY_2V_CAST( DST, SRC, CAST ) \ 533848b8605Smrgdo { \ 534848b8605Smrg (DST)[0] = (CAST)(SRC)[0]; \ 535848b8605Smrg (DST)[1] = (CAST)(SRC)[1]; \ 536848b8605Smrg} while (0) 537848b8605Smrg 538848b8605Smrg/** Copy a 2-element float vector */ 539848b8605Smrg#define COPY_2FV( DST, SRC ) \ 540848b8605Smrgdo { \ 541848b8605Smrg const GLfloat *_tmp = (SRC); \ 542848b8605Smrg (DST)[0] = _tmp[0]; \ 543848b8605Smrg (DST)[1] = _tmp[1]; \ 544848b8605Smrg} while (0) 545848b8605Smrg 546848b8605Smrg/** Subtraction */ 547848b8605Smrg#define SUB_2V( DST, SRCA, SRCB ) \ 548848b8605Smrgdo { \ 549848b8605Smrg (DST)[0] = (SRCA)[0] - (SRCB)[0]; \ 550848b8605Smrg (DST)[1] = (SRCA)[1] - (SRCB)[1]; \ 551848b8605Smrg} while (0) 552848b8605Smrg 553848b8605Smrg/** Addition */ 554848b8605Smrg#define ADD_2V( DST, SRCA, SRCB ) \ 555848b8605Smrgdo { \ 556848b8605Smrg (DST)[0] = (SRCA)[0] + (SRCB)[0]; \ 557848b8605Smrg (DST)[1] = (SRCA)[1] + (SRCB)[1]; \ 558848b8605Smrg} while (0) 559848b8605Smrg 560848b8605Smrg/** In-place scalar multiplication */ 561848b8605Smrg#define SCALE_2V( DST, SRCA, SRCB ) \ 562848b8605Smrgdo { \ 563848b8605Smrg (DST)[0] = (SRCA)[0] * (SRCB)[0]; \ 564848b8605Smrg (DST)[1] = (SRCA)[1] * (SRCB)[1]; \ 565848b8605Smrg} while (0) 566848b8605Smrg 567848b8605Smrg/** In-place addition */ 568848b8605Smrg#define ACC_2V( DST, SRC ) \ 569848b8605Smrgdo { \ 570848b8605Smrg (DST)[0] += (SRC)[0]; \ 571848b8605Smrg (DST)[1] += (SRC)[1]; \ 572848b8605Smrg} while (0) 573848b8605Smrg 574848b8605Smrg/** Element-wise multiplication and addition */ 575848b8605Smrg#define ACC_SCALE_2V( DST, SRCA, SRCB ) \ 576848b8605Smrgdo { \ 577848b8605Smrg (DST)[0] += (SRCA)[0] * (SRCB)[0]; \ 578848b8605Smrg (DST)[1] += (SRCA)[1] * (SRCB)[1]; \ 579848b8605Smrg} while (0) 580848b8605Smrg 581848b8605Smrg/** Scalar multiplication */ 582848b8605Smrg#define SCALE_SCALAR_2V( DST, S, SRCB ) \ 583848b8605Smrgdo { \ 584848b8605Smrg (DST)[0] = S * (SRCB)[0]; \ 585848b8605Smrg (DST)[1] = S * (SRCB)[1]; \ 586848b8605Smrg} while (0) 587848b8605Smrg 588848b8605Smrg/** In-place scalar multiplication and addition */ 589848b8605Smrg#define ACC_SCALE_SCALAR_2V( DST, S, SRCB ) \ 590848b8605Smrgdo { \ 591848b8605Smrg (DST)[0] += S * (SRCB)[0]; \ 592848b8605Smrg (DST)[1] += S * (SRCB)[1]; \ 593848b8605Smrg} while (0) 594848b8605Smrg 595848b8605Smrg/** In-place scalar multiplication */ 596848b8605Smrg#define SELF_SCALE_SCALAR_2V( DST, S ) \ 597848b8605Smrgdo { \ 598848b8605Smrg (DST)[0] *= S; \ 599848b8605Smrg (DST)[1] *= S; \ 600848b8605Smrg} while (0) 601848b8605Smrg 602848b8605Smrg/** In-place scalar addition */ 603848b8605Smrg#define ACC_SCALAR_2V( DST, S ) \ 604848b8605Smrgdo { \ 605848b8605Smrg (DST)[0] += S; \ 606848b8605Smrg (DST)[1] += S; \ 607848b8605Smrg} while (0) 608848b8605Smrg 609848b8605Smrg/** Assign scalers to short vectors */ 610848b8605Smrg#define ASSIGN_2V( V, V0, V1 ) \ 611848b8605Smrgdo { \ 612848b8605Smrg V[0] = V0; \ 613848b8605Smrg V[1] = V1; \ 614848b8605Smrg} while(0) 615848b8605Smrg 616848b8605Smrg/*@}*/ 617848b8605Smrg 618848b8605Smrg/** Copy \p sz elements into a homegeneous (4-element) vector, giving 619848b8605Smrg * default values to the remaining components. 620848b8605Smrg * The default values are chosen based on \p type. 621848b8605Smrg */ 622848b8605Smrgstatic inline void 623848b8605SmrgCOPY_CLEAN_4V_TYPE_AS_FLOAT(GLfloat dst[4], int sz, const GLfloat src[4], 624848b8605Smrg GLenum type) 625848b8605Smrg{ 626848b8605Smrg switch (type) { 627848b8605Smrg case GL_FLOAT: 628848b8605Smrg ASSIGN_4V(dst, 0, 0, 0, 1); 629848b8605Smrg break; 630848b8605Smrg case GL_INT: 631848b8605Smrg ASSIGN_4V(dst, INT_AS_FLT(0), INT_AS_FLT(0), 632848b8605Smrg INT_AS_FLT(0), INT_AS_FLT(1)); 633848b8605Smrg break; 634848b8605Smrg case GL_UNSIGNED_INT: 635848b8605Smrg ASSIGN_4V(dst, UINT_AS_FLT(0), UINT_AS_FLT(0), 636848b8605Smrg UINT_AS_FLT(0), UINT_AS_FLT(1)); 637848b8605Smrg break; 638848b8605Smrg default: 639848b8605Smrg ASSIGN_4V(dst, 0.0f, 0.0f, 0.0f, 1.0f); /* silence warnings */ 640848b8605Smrg ASSERT(!"Unexpected type in COPY_CLEAN_4V_TYPE_AS_FLOAT macro"); 641848b8605Smrg } 642848b8605Smrg COPY_SZ_4V(dst, sz, src); 643848b8605Smrg} 644848b8605Smrg 645848b8605Smrg/** \name Linear interpolation functions */ 646848b8605Smrg/*@{*/ 647848b8605Smrg 648848b8605Smrgstatic inline GLfloat 649848b8605SmrgLINTERP(GLfloat t, GLfloat out, GLfloat in) 650848b8605Smrg{ 651848b8605Smrg return out + t * (in - out); 652848b8605Smrg} 653848b8605Smrg 654848b8605Smrgstatic inline void 655848b8605SmrgINTERP_3F(GLfloat t, GLfloat dst[3], const GLfloat out[3], const GLfloat in[3]) 656848b8605Smrg{ 657848b8605Smrg dst[0] = LINTERP( t, out[0], in[0] ); 658848b8605Smrg dst[1] = LINTERP( t, out[1], in[1] ); 659848b8605Smrg dst[2] = LINTERP( t, out[2], in[2] ); 660848b8605Smrg} 661848b8605Smrg 662848b8605Smrgstatic inline void 663848b8605SmrgINTERP_4F(GLfloat t, GLfloat dst[4], const GLfloat out[4], const GLfloat in[4]) 664848b8605Smrg{ 665848b8605Smrg dst[0] = LINTERP( t, out[0], in[0] ); 666848b8605Smrg dst[1] = LINTERP( t, out[1], in[1] ); 667848b8605Smrg dst[2] = LINTERP( t, out[2], in[2] ); 668848b8605Smrg dst[3] = LINTERP( t, out[3], in[3] ); 669848b8605Smrg} 670848b8605Smrg 671848b8605Smrg/*@}*/ 672848b8605Smrg 673848b8605Smrg 674848b8605Smrg 675848b8605Smrg/** Clamp X to [MIN,MAX] */ 676848b8605Smrg#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) ) 677848b8605Smrg 678848b8605Smrg/** Minimum of two values: */ 679848b8605Smrg#define MIN2( A, B ) ( (A)<(B) ? (A) : (B) ) 680848b8605Smrg 681848b8605Smrg/** Maximum of two values: */ 682848b8605Smrg#define MAX2( A, B ) ( (A)>(B) ? (A) : (B) ) 683848b8605Smrg 684848b8605Smrg/** Minimum and maximum of three values: */ 685848b8605Smrg#define MIN3( A, B, C ) ((A) < (B) ? MIN2(A, C) : MIN2(B, C)) 686848b8605Smrg#define MAX3( A, B, C ) ((A) > (B) ? MAX2(A, C) : MAX2(B, C)) 687848b8605Smrg 688848b8605Smrgstatic inline unsigned 689848b8605Smrgminify(unsigned value, unsigned levels) 690848b8605Smrg{ 691848b8605Smrg return MAX2(1, value >> levels); 692848b8605Smrg} 693848b8605Smrg 694848b8605Smrg/** 695848b8605Smrg * Return true if the given value is a power of two. 696848b8605Smrg * 697848b8605Smrg * Note that this considers 0 a power of two. 698848b8605Smrg */ 699848b8605Smrgstatic inline bool 700848b8605Smrgis_power_of_two(unsigned value) 701848b8605Smrg{ 702848b8605Smrg return (value & (value - 1)) == 0; 703848b8605Smrg} 704848b8605Smrg 705848b8605Smrg/** 706848b8605Smrg * Align a value up to an alignment value 707848b8605Smrg * 708848b8605Smrg * If \c value is not already aligned to the requested alignment value, it 709848b8605Smrg * will be rounded up. 710848b8605Smrg * 711848b8605Smrg * \param value Value to be rounded 712848b8605Smrg * \param alignment Alignment value to be used. This must be a power of two. 713848b8605Smrg * 714848b8605Smrg * \sa ROUND_DOWN_TO() 715848b8605Smrg */ 716848b8605Smrg#define ALIGN(value, alignment) (((value) + (alignment) - 1) & ~((alignment) - 1)) 717848b8605Smrg 718848b8605Smrg/** 719848b8605Smrg * Align a value down to an alignment value 720848b8605Smrg * 721848b8605Smrg * If \c value is not already aligned to the requested alignment value, it 722848b8605Smrg * will be rounded down. 723848b8605Smrg * 724848b8605Smrg * \param value Value to be rounded 725848b8605Smrg * \param alignment Alignment value to be used. This must be a power of two. 726848b8605Smrg * 727848b8605Smrg * \sa ALIGN() 728848b8605Smrg */ 729848b8605Smrg#define ROUND_DOWN_TO(value, alignment) ((value) & ~(alignment - 1)) 730848b8605Smrg 731848b8605Smrg 732848b8605Smrg/** Cross product of two 3-element vectors */ 733848b8605Smrgstatic inline void 734848b8605SmrgCROSS3(GLfloat n[3], const GLfloat u[3], const GLfloat v[3]) 735848b8605Smrg{ 736848b8605Smrg n[0] = u[1] * v[2] - u[2] * v[1]; 737848b8605Smrg n[1] = u[2] * v[0] - u[0] * v[2]; 738848b8605Smrg n[2] = u[0] * v[1] - u[1] * v[0]; 739848b8605Smrg} 740848b8605Smrg 741848b8605Smrg 742848b8605Smrg/** Dot product of two 2-element vectors */ 743848b8605Smrgstatic inline GLfloat 744848b8605SmrgDOT2(const GLfloat a[2], const GLfloat b[2]) 745848b8605Smrg{ 746848b8605Smrg return a[0] * b[0] + a[1] * b[1]; 747848b8605Smrg} 748848b8605Smrg 749848b8605Smrgstatic inline GLfloat 750848b8605SmrgDOT3(const GLfloat a[3], const GLfloat b[3]) 751848b8605Smrg{ 752848b8605Smrg return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; 753848b8605Smrg} 754848b8605Smrg 755848b8605Smrgstatic inline GLfloat 756848b8605SmrgDOT4(const GLfloat a[4], const GLfloat b[4]) 757848b8605Smrg{ 758848b8605Smrg return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; 759848b8605Smrg} 760848b8605Smrg 761848b8605Smrg 762848b8605Smrgstatic inline GLfloat 763848b8605SmrgLEN_SQUARED_3FV(const GLfloat v[3]) 764848b8605Smrg{ 765848b8605Smrg return DOT3(v, v); 766848b8605Smrg} 767848b8605Smrg 768848b8605Smrgstatic inline GLfloat 769848b8605SmrgLEN_SQUARED_2FV(const GLfloat v[2]) 770848b8605Smrg{ 771848b8605Smrg return DOT2(v, v); 772848b8605Smrg} 773848b8605Smrg 774848b8605Smrg 775848b8605Smrgstatic inline GLfloat 776848b8605SmrgLEN_3FV(const GLfloat v[3]) 777848b8605Smrg{ 778848b8605Smrg return sqrtf(LEN_SQUARED_3FV(v)); 779848b8605Smrg} 780848b8605Smrg 781848b8605Smrgstatic inline GLfloat 782848b8605SmrgLEN_2FV(const GLfloat v[2]) 783848b8605Smrg{ 784848b8605Smrg return sqrtf(LEN_SQUARED_2FV(v)); 785848b8605Smrg} 786848b8605Smrg 787848b8605Smrg 788848b8605Smrg/* Normalize a 3-element vector to unit length. */ 789848b8605Smrgstatic inline void 790848b8605SmrgNORMALIZE_3FV(GLfloat v[3]) 791848b8605Smrg{ 792848b8605Smrg GLfloat len = (GLfloat) LEN_SQUARED_3FV(v); 793848b8605Smrg if (len) { 794848b8605Smrg len = INV_SQRTF(len); 795848b8605Smrg v[0] *= len; 796848b8605Smrg v[1] *= len; 797848b8605Smrg v[2] *= len; 798848b8605Smrg } 799848b8605Smrg} 800848b8605Smrg 801848b8605Smrg 802848b8605Smrg/** Is float value negative? */ 803848b8605Smrgstatic inline GLboolean 804848b8605SmrgIS_NEGATIVE(float x) 805848b8605Smrg{ 806848b8605Smrg return signbit(x) != 0; 807848b8605Smrg} 808848b8605Smrg 809848b8605Smrg/** Test two floats have opposite signs */ 810848b8605Smrgstatic inline GLboolean 811848b8605SmrgDIFFERENT_SIGNS(GLfloat x, GLfloat y) 812848b8605Smrg{ 813848b8605Smrg return signbit(x) != signbit(y); 814848b8605Smrg} 815848b8605Smrg 816848b8605Smrg 817848b8605Smrg/** Compute ceiling of integer quotient of A divided by B. */ 818848b8605Smrg#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) 819848b8605Smrg 820848b8605Smrg 821848b8605Smrg/** casts to silence warnings with some compilers */ 822848b8605Smrg#define ENUM_TO_INT(E) ((GLint)(E)) 823848b8605Smrg#define ENUM_TO_FLOAT(E) ((GLfloat)(GLint)(E)) 824848b8605Smrg#define ENUM_TO_DOUBLE(E) ((GLdouble)(GLint)(E)) 825848b8605Smrg#define ENUM_TO_BOOLEAN(E) ((E) ? GL_TRUE : GL_FALSE) 826848b8605Smrg 827848b8605Smrg/* Compute the size of an array */ 828848b8605Smrg#ifndef ARRAY_SIZE 829848b8605Smrg# define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 830848b8605Smrg#endif 831848b8605Smrg 832848b8605Smrg/* Stringify */ 833848b8605Smrg#define STRINGIFY(x) #x 834848b8605Smrg 835848b8605Smrg#endif 836