/*----------------------------------------------------------------- LOG GEM - Graphics Environment for Multimedia GemFuncUtil.h - contains functions for graphics - part of GEM Copyright (c) 1997-2000 Mark Danks. mark@danks.org Copyright (c) Günther Geiger. geiger@epy.co.at Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at For information on usage and redistribution, and for a DISCLAIMER OF ALL WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. -----------------------------------------------------------------*/ #ifndef _INCLUDE__GEM_UTILS_FUNCTIONS_H_ #define _INCLUDE__GEM_UTILS_FUNCTIONS_H_ #include "Gem/ExportDef.h" /* this should be included for ALL platforms: * should we define __MMX__ for windows in there ? */ #include "Utils/SIMD.h" #include "Utils/GemMath.h" // for rand() #include /////////////////////////////////////////////////////////////////////////////// // powerOfTwo // get the next higher 2^n-number (if value isn't 2^n by itself) /////////////////////////////////////////////////////////////////////////////// inline int powerOfTwo(int value) { /* int x = 1; // while(x <= value) x <<= 1; while(x < value) x <<= 1; return(x); */ // optimization from "Hacker's Delight" // - above loop executes in 4n+3 instructions, where n is the power of 2 of returned int // - below code is branch-free and only 12 instructions! value = value - 1; value = value | (value >> 1); value = value | (value >> 2); value = value | (value >> 4); value = value | (value >> 8); value = value | (value >> 16); return (value + 1); } /////////////////////////////////////////////////////////////////////////////// // min/max functions // /////////////////////////////////////////////////////////////////////////////// #ifndef MIN template inline T MIN(T x, T y) { return (x inline T MAX(T x, T y) { return (x>y)?x:y; } #endif template inline T TRI_MAX(T v1, T v2, T v3) { if (v1 > v2 && v1 > v3) { return(v1); } if (v2 > v3) { return(v2); } return(v3); } template inline T TRI_MIN(T v1, T v2, T v3) { if (v1 < v2 && v1 < v3) { return(v1); } if (v2 < v3) { return(v2); } return(v3); } /////////////////////////////////////////////////////////////////////////////// // Clamp functions // /////////////////////////////////////////////////////////////////////////////// ////////// // Clamp a value high inline unsigned char CLAMP_HIGH(int x) { return((unsigned char )((x > 255) ? 255 : x)); } ////////// // Clamp a value low inline unsigned char CLAMP_LOW(int x) { return((unsigned char )((x < 0) ? 0 : x)); } ////////// // Clamp an int to the range of an unsigned char inline unsigned char CLAMP(int x) { return((unsigned char)((x > 255) ? 255 : ( (x < 0) ? 0 : x))); } ////////// // Clamp a float to the range of an unsigned char template inline unsigned char CLAMP(T x) { return((unsigned char)((x > (T)255) ? (T)255 : ( (x < (T)0) ? (T)0 : x))); } ////////// // Clamp a float to 0. <= x <= 1.0 template inline float FLOAT_CLAMP(T x) { return((x > 1.) ? 1. : ( (x < 0.) ? 0. : x)); } ///////// // Clamp the Y channel of YUV (16%235) inline unsigned char CLAMP_Y(int x) { return((unsigned char)((x > 235) ? 235 : ( (x < 16) ? 16 : x))); } /////////////////////////////////////////////////////////////////////////////// // Multiply and interpolation // /////////////////////////////////////////////////////////////////////////////// ////////// // Exactly multiply two unsigned chars // This avoids a float value (important on Intel...) // From Alvy Ray Smith paper inline unsigned char INT_MULT(unsigned int a, unsigned int b) { int t = (unsigned int)a * (unsigned int)b + 0x80; return((unsigned char)(((t >> 8) + t) >> 8)); } ////////// // Exactly LERPs two values // This avoids a float value (important on Intel...) // From Alvy Ray Smith paper inline unsigned char INT_LERP(unsigned int p, unsigned int q, unsigned int a) { return((unsigned char)(p + INT_MULT(a, q - p))); } ////////// // Floating point LERP template inline T FLOAT_LERP(T p, T q, T a) { return( a * (q - p) + p); } /////////////////////////////////////////////////////////////////////////////// // Step function // /////////////////////////////////////////////////////////////////////////////// template inline int stepFunc(T x, T a) { return(x >= a); } /////////////////////////////////////////////////////////////////////////////// // Pulse function // /////////////////////////////////////////////////////////////////////////////// template inline int pulseFunc(T x, T a, T b) { return(stepFunc(a, x) - stepFunc(b, x)); } /////////////////////////////////////////////////////////////////////////////// // Clamp function // /////////////////////////////////////////////////////////////////////////////// template inline T clampFunc(T x, T a, T b) { return(x < a ? a : (x > b ? b : x)); } /* inline void* clampFunc(void* x, void* a, void* b) { return(x < a ? a : (x > b ? b : x)); } */ /* inline int GateInt(int nValue,int nMin,int nMax) inline float GateFlt(float nValue,float nMin,float nMax) inline void* GatePtr(void* pValue,void* pMin,void* pMax) */ /////////////////////////////////////////////////////////////////////////////// // absolute integer // /////////////////////////////////////////////////////////////////////////////// inline int AbsInt(int inValue) { return (inValue>0)?inValue:-inValue; } static inline int GetSign(int inValue) { return (inValue<0)?-1:1; } /////////////////////////////////////////////////////////////////////////////// // wrapping functions for integers // /////////////////////////////////////////////////////////////////////////////// inline int GetTiled(int inValue,const int nMax) { int nOutValue=(inValue%nMax); if (nOutValue<0) { nOutValue=((nMax-1)+nOutValue); } return nOutValue; } inline int GetMirrored(int inValue,const int nMax) { const int nTwoMax=(nMax*2); int nOutValue=GetTiled(inValue,nTwoMax); if (nOutValue>=nMax) { nOutValue=((nTwoMax-1)-nOutValue); } return nOutValue; } /////////////////////////////////////////////////////////////////////////////// // 2D-algebra // /////////////////////////////////////////////////////////////////////////////// static inline void Get2dTangent(float inX,float inY,float* poutX, float* poutY) { *poutX=inY; *poutY=-inX; } /////////////////////////////////////////////////////////////////////////////// // 2D-dot product /////////////////////////////////////////////////////////////////////////////// static inline float Dot2d(float Ax,float Ay,float Bx,float By) { return ((Ax*Bx)+(Ay*By)); } /////////////////////////////////////////////////////////////////////////////// // 2D-vector normalization /////////////////////////////////////////////////////////////////////////////// static inline void Normalise2d(float* pX,float* pY) { const float MagSqr=Dot2d(*pX,*pY,*pX,*pY); float Magnitude=(float)sqrt(MagSqr); if (Magnitude<=0.0f) { Magnitude=0.001f; } const float RecipMag=1.0f/Magnitude; *pX*=RecipMag; *pY*=RecipMag; } /////////////////////////////////////////////////////////////////////////////// // higher algebra // /////////////////////////////////////////////////////////////////////////////// inline float GetRandomFloat(void) { return rand()/static_cast(RAND_MAX); } /////////////////////////////////////////////////////////////////////////////// // Smooth step function (3x^2 - 2x^3) // /////////////////////////////////////////////////////////////////////////////// GEM_EXTERN extern float smoothStep(float x, float a, float b); GEM_EXTERN extern int smoothStep(int x, int a, int b); GEM_EXTERN extern unsigned char smoothStep(unsigned char x, unsigned char a, unsigned char b); /////////////////////////////////////////////////////////////////////////////// // Bias function // // Remap unit interval (curve) // If a == 0.5, then is linear mapping. /////////////////////////////////////////////////////////////////////////////// GEM_EXTERN extern float biasFunc(float x, float a); /////////////////////////////////////////////////////////////////////////////// // Gain function // // Remap unit interval (S-curve) // Will always return 0.5 when x is 0.5 // If a == 0.5, then is linear mapping. /////////////////////////////////////////////////////////////////////////////// GEM_EXTERN extern float gainFunc(float x, float a); /////////////////////////////////////////////////////////////////////////////// // Linear function // // val should be 0 <= val <= 1. // ret should point at a float of enough dimensions to hold the returned value // For instance, numDimen == 2, should have a ret[2] // numDimen is the number of dimensions to compute // npnts is the number of points per dimension. // /////////////////////////////////////////////////////////////////////////////// GEM_EXTERN extern void linearFunc(float val, float *ret, int numDimen, int npnts, float *pnts); GEM_EXTERN extern void linearFunc(double val, double *ret, int numDimen, int npnts, double *pnts); /////////////////////////////////////////////////////////////////////////////// // Spline function // // val should be 0 <= val <= 1. // ret should point at a float of enough dimensions to hold the returned value // For instance, numDimen == 2, should have a ret[2] // numDimen is the number of dimensions to compute // nknots is the number of knots per dimension. // There must be at least four knots! // // Thanks to // _Texturing and Modeling: A Procedural Approach_ // David S. Ebert, Ed. /////////////////////////////////////////////////////////////////////////////// GEM_EXTERN extern void splineFunc(float val, float *ret, int numDimen, int nknots, float *knot); GEM_EXTERN extern void splineFunc(double val, double *ret, int numDimen, int nknots, double *knot); /////////////////////////////////////////////////////////////////////////////// // Pixel access functions // /////////////////////////////////////////////////////////////////////////////// // // Accelerated Pixel Manipulations // This is sort on a vector operation on 8 chars at the same time .... could be // implemented in MMX // Alpha channel is not added !! (would be nr 3 and 7) #define ADD8_NOALPHA(a,b) \ ((unsigned char*)(a))[0] = CLAMP_HIGH((int)((unsigned char*)(a))[0] + ((unsigned char*)(b))[0]);\ ((unsigned char*)(a))[1] = CLAMP_HIGH((int)((unsigned char*)(a))[1] + ((unsigned char*)(b))[1]);\ ((unsigned char*)(a))[2] = CLAMP_HIGH((int)((unsigned char*)(a))[2] + ((unsigned char*)(b))[2]);\ ((unsigned char*)(a))[4] = CLAMP_HIGH((int)((unsigned char*)(a))[4] + ((unsigned char*)(b))[4]);\ ((unsigned char*)(a))[5] = CLAMP_HIGH((int)((unsigned char*)(a))[5] + ((unsigned char*)(b))[5]);\ ((unsigned char*)(a))[6] = CLAMP_HIGH((int)((unsigned char*)(a))[6] + ((unsigned char*)(b))[6]);\ #define SUB8_NOALPHA(a,b) \ ((unsigned char*)(a))[0] = CLAMP_LOW((int)((unsigned char*)(a))[0] - ((unsigned char*)(b))[0]);\ ((unsigned char*)(a))[1] = CLAMP_LOW((int)((unsigned char*)(a))[1] - ((unsigned char*)(b))[1]);\ ((unsigned char*)(a))[2] = CLAMP_LOW((int)((unsigned char*)(a))[2] - ((unsigned char*)(b))[2]);\ ((unsigned char*)(a))[4] = CLAMP_LOW((int)((unsigned char*)(a))[4] - ((unsigned char*)(b))[4]);\ ((unsigned char*)(a))[5] = CLAMP_LOW((int)((unsigned char*)(a))[5] - ((unsigned char*)(b))[5]);\ ((unsigned char*)(a))[6] = CLAMP_LOW((int)((unsigned char*)(a))[6] - ((unsigned char*)(b))[6]);\ #define ADD8(a,b) \ ((unsigned char*)(a))[0] = CLAMP_HIGH((int)((unsigned char*)(a))[0] + ((unsigned char*)(b))[0]);\ ((unsigned char*)(a))[1] = CLAMP_HIGH((int)((unsigned char*)(a))[1] + ((unsigned char*)(b))[1]);\ ((unsigned char*)(a))[2] = CLAMP_HIGH((int)((unsigned char*)(a))[2] + ((unsigned char*)(b))[2]);\ ((unsigned char*)(a))[3] = CLAMP_HIGH((int)((unsigned char*)(a))[3] + ((unsigned char*)(b))[3]);\ ((unsigned char*)(a))[4] = CLAMP_HIGH((int)((unsigned char*)(a))[4] + ((unsigned char*)(b))[4]);\ ((unsigned char*)(a))[5] = CLAMP_HIGH((int)((unsigned char*)(a))[5] + ((unsigned char*)(b))[5]);\ ((unsigned char*)(a))[6] = CLAMP_HIGH((int)((unsigned char*)(a))[6] + ((unsigned char*)(b))[6]);\ ((unsigned char*)(a))[7] = CLAMP_HIGH((int)((unsigned char*)(a))[7] + ((unsigned char*)(b))[7]);\ #define SUB8(a,b) \ ((unsigned char*)(a))[0] = CLAMP_LOW((int)((unsigned char*)(a))[0] - ((unsigned char*)(b))[0]);\ ((unsigned char*)(a))[1] = CLAMP_LOW((int)((unsigned char*)(a))[1] - ((unsigned char*)(b))[1]);\ ((unsigned char*)(a))[2] = CLAMP_LOW((int)((unsigned char*)(a))[2] - ((unsigned char*)(b))[2]);\ ((unsigned char*)(a))[3] = CLAMP_LOW((int)((unsigned char*)(a))[3] - ((unsigned char*)(b))[3]);\ ((unsigned char*)(a))[4] = CLAMP_LOW((int)((unsigned char*)(a))[4] - ((unsigned char*)(b))[4]);\ ((unsigned char*)(a))[5] = CLAMP_LOW((int)((unsigned char*)(a))[5] - ((unsigned char*)(b))[5]);\ ((unsigned char*)(a))[6] = CLAMP_LOW((int)((unsigned char*)(a))[6] - ((unsigned char*)(b))[6]);\ ((unsigned char*)(a))[7] = CLAMP_LOW((int)((unsigned char*)(a))[7] - ((unsigned char*)(b))[7]);\ #ifdef __APPLE__ //Ian Ollman's function to determine the cache prefetch for altivec vec_dst() #include inline uint32_t GetPrefetchConstant( int blockSizeInVectors, int blockCount, int blockStride ) { return ((blockSizeInVectors << 24) & 0x1F000000) | (( blockCount << 16) & 0x00FF0000) | (blockStride & 0xFFFF); } #endif #endif // for header file