#ifndef SYNTAX_GLSL
#define SYNTAX_GLSL

const float PI = 3.14159265358;

// macro wizardry by BruceKnowsHow
#define DEFINE_genFType(func)                                                  \
  func ( float ) func ( vec2 ) func ( vec3 ) func ( vec4 )
#define DEFINE_genVType(func) func ( vec2 ) func ( vec3 ) func ( vec4 )
#define DEFINE_genDType(func)                                                  \
  func ( double ) func ( dvec2 ) func ( dvec3 ) func ( dvec4 )
#define DEFINE_genIType(func)                                                  \
  func ( int ) func ( ivec2 ) func ( ivec3 ) func ( ivec4 )
#define DEFINE_genUType(func)                                                  \
  func ( uint ) func ( uvec2 ) func ( uvec3 ) func ( uvec4 )
#define DEFINE_genBType(func)                                                  \
  func ( bool ) func ( bvec2 ) func ( bvec3 ) func ( bvec4 )

#define rcp_(type)                                                             \
  type rcp(type x) {                                                           \
    return 1.0 / x;                                                            \
  }
#define pow2_(type)                                                            \
  type pow2(type x) {                                                          \
    return x * x;                                                              \
  }
#define pow3_(type)                                                            \
  type pow3(type x) {                                                          \
    return x * x * x;                                                          \
  }
#define pow4_(type)                                                            \
  type pow4(type x) {                                                          \
    x *= x;                                                                    \
    return x * x;                                                              \
  }
#define pow5_(type)                                                            \
  type pow5(type x) {                                                          \
    type x2 = x * x;                                                           \
    return x2 * x2 * x;                                                        \
  }
#define pow6_(type)                                                            \
  type pow6(type x) {                                                          \
    type x2 = x * x;                                                           \
    return x2 * x2 * x2;                                                       \
  }
#define pow7_(type)                                                            \
  type pow7(type x) {                                                          \
    type x2 = x * x;                                                           \
    return x2 * x2 * x2 * x;                                                   \
  }
#define pow8_(type)                                                            \
  type pow8(type x) {                                                          \
    x *= x;                                                                    \
    x *= x;                                                                    \
    return x * x;                                                              \
  }

DEFINE_genFType(rcp_)
DEFINE_genFType(pow2_)
DEFINE_genFType(pow3_)
DEFINE_genFType(pow4_)
DEFINE_genFType(pow5_)
DEFINE_genFType(pow6_)
DEFINE_genFType(pow7_)
DEFINE_genFType(pow8_)

#define max0(x) max(x, 0.0)
#define max1(x) max(x, 1.0)
#define min0(x) min(x, 0.0)
#define min1(x) min(x, 1.0)

#define min3(x, y, z) min(x, min(y, z))
#define min4(x, y, z, w) min(min(x, y), min(z, w))

// TODO: this is not optimal

#define minVec2(v) min((v).x, (v).y)
#define minVec3(v) min((v).x, min((v).y, (v).z))
#define minVec4(v) min(min((v).x, (v).y), min((v).z, (v).w))

#define max3(x, y, z) max(x, max(y, z))
#define max4(x, y, z, w) max(max(x, y), max(z, w))

#define maxVec2(v) max((v).x, (v).y)
#define maxVec3(v) max((v).x, max((v).y, (v).z))
#define maxVec4(v) max(max((v).x, (v).y), max((v).z, (v).w))

#define sumVec2(v) ((v).x + (v).y)
#define sumVec3(v) ((v).x + (v).y + (v).z)
#define sumVec4(v) ((v).x + (v).y + ((v).z + (v).w))

#define clamp01(x) clamp(x, 0.0, 1.0)

#define saturate clamp01
#define lerp mix

#define RED vec3(1.0, 0.0, 0.0)
#define GREEN vec3(0.0, 1.0, 0.0)
#define BLUE vec3(0.0, 0.0, 1.0)

#endif // SYNTAX_GLSL
