// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#pragma once

struct Vec3f 
{
  float x;
  float y;
  float z;
};

////////////////////////////////////////////////////////////////////////////////
/// Constructors
////////////////////////////////////////////////////////////////////////////////

inline uniform Vec3f make_Vec3f(const uniform float a) { uniform Vec3f v; v.x = a; v.y = a; v.z = a; return v; }
inline varying Vec3f make_Vec3f(const varying float a) { varying Vec3f v; v.x = a; v.y = a; v.z = a; return v; }

inline uniform Vec3f make_Vec3f(const uniform float x, const uniform float y, const uniform float z) { uniform Vec3f v; v.x = x; v.y = y; v.z = z; return v; }
inline varying Vec3f make_Vec3f(const varying float x, const varying float y, const varying float z) { varying Vec3f v; v.x = x; v.y = y; v.z = z; return v; }

////////////////////////////////////////////////////////////////////////////////
/// Unary Operators
////////////////////////////////////////////////////////////////////////////////

inline uniform Vec3f operator-(const uniform Vec3f a) { return make_Vec3f(-a.x,-a.y,-a.z); }
inline varying Vec3f operator-(const varying Vec3f a) { return make_Vec3f(-a.x,-a.y,-a.z); }

inline uniform Vec3f neg(const uniform Vec3f a) { return make_Vec3f(-a.x,-a.y,-a.z); }
inline varying Vec3f neg(const varying Vec3f a) { return make_Vec3f(-a.x,-a.y,-a.z); }

inline uniform Vec3f abs(const uniform Vec3f a) { return make_Vec3f(abs(a.x),abs(a.y),abs(a.z)); }
inline varying Vec3f abs(const varying Vec3f a) { return make_Vec3f(abs(a.x),abs(a.y),abs(a.z)); }

inline uniform Vec3f rcp(const uniform Vec3f a) { return make_Vec3f(rcp(a.x),rcp(a.y),rcp(a.z)); }
inline varying Vec3f rcp(const varying Vec3f a) { return make_Vec3f(rcp(a.x),rcp(a.y),rcp(a.z)); }

inline uniform Vec3f rcp_safe(const uniform Vec3f a) { return make_Vec3f(rcp_safe(a.x), rcp_safe(a.y), rcp_safe(a.z)); }
inline varying Vec3f rcp_safe(const varying Vec3f a) { return make_Vec3f(rcp_safe(a.x), rcp_safe(a.y), rcp_safe(a.z)); }

inline uniform Vec3f exp(const uniform Vec3f a) { return make_Vec3f(exp(a.x),exp(a.y),exp(a.z)); }
inline varying Vec3f exp(const varying Vec3f a) { return make_Vec3f(exp(a.x),exp(a.y),exp(a.z)); }

////////////////////////////////////////////////////////////////////////////////
/// Binary Operators
////////////////////////////////////////////////////////////////////////////////

inline uniform Vec3f operator+(const uniform Vec3f a, const uniform Vec3f b) { return make_Vec3f(a.x+b.x, a.y+b.y, a.z+b.z); }
inline varying Vec3f operator+(const varying Vec3f a, const varying Vec3f b) { return make_Vec3f(a.x+b.x, a.y+b.y, a.z+b.z); }

inline uniform Vec3f operator-(const uniform Vec3f a, const uniform Vec3f b) { return make_Vec3f(a.x-b.x, a.y-b.y, a.z-b.z); }
inline varying Vec3f operator-(const varying Vec3f a, const varying Vec3f b) { return make_Vec3f(a.x-b.x, a.y-b.y, a.z-b.z); }

inline uniform Vec3f operator*(const uniform float a, const uniform Vec3f b) { return make_Vec3f(a*b.x, a*b.y, a*b.z); }
inline varying Vec3f operator*(const varying float a, const varying Vec3f b) { return make_Vec3f(a*b.x, a*b.y, a*b.z); }

inline uniform Vec3f operator*(const uniform Vec3f a, const uniform float b) { return make_Vec3f(a.x*b, a.y*b, a.z*b); }
inline varying Vec3f operator*(const varying Vec3f a, const varying float b) { return make_Vec3f(a.x*b, a.y*b, a.z*b); }

inline uniform Vec3f operator*(const uniform Vec3f a, const uniform Vec3f b) { return make_Vec3f(a.x*b.x, a.y*b.y, a.z*b.z); }
inline varying Vec3f operator*(const varying Vec3f a, const varying Vec3f b) { return make_Vec3f(a.x*b.x, a.y*b.y, a.z*b.z); }

inline uniform Vec3f operator/(const uniform float a, const uniform Vec3f b) { return make_Vec3f(a/b.x, a/b.y, a/b.z); }
inline varying Vec3f operator/(const varying float a, const varying Vec3f b) { return make_Vec3f(a/b.x, a/b.y, a/b.z); }

inline uniform Vec3f operator/(const uniform Vec3f a, const uniform float b) { return make_Vec3f(a.x/b, a.y/b, a.z/b); }
inline varying Vec3f operator/(const varying Vec3f a, const varying float b) { return make_Vec3f(a.x/b, a.y/b, a.z/b); }

inline uniform Vec3f operator/(const uniform Vec3f a, const uniform Vec3f b) { return make_Vec3f(a.x/b.x, a.y/b.y, a.z/b.z); }
inline varying Vec3f operator/(const varying Vec3f a, const varying Vec3f b) { return make_Vec3f(a.x/b.x, a.y/b.y, a.z/b.z); }

inline uniform Vec3f min(const uniform Vec3f a, const uniform Vec3f b) { return make_Vec3f(min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); }
inline varying Vec3f min(const varying Vec3f a, const varying Vec3f b) { return make_Vec3f(min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); }

inline uniform Vec3f max(const uniform Vec3f a, const uniform Vec3f b) { return make_Vec3f(max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); }
inline varying Vec3f max(const varying Vec3f a, const varying Vec3f b) { return make_Vec3f(max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); }

inline uniform Vec3f pow(const uniform Vec3f a, const uniform float b) { return make_Vec3f(pow(a.x,b), pow(a.y,b), pow(a.z,b)); }
inline varying Vec3f pow(const varying Vec3f a, const varying float b) { return make_Vec3f(pow(a.x,b), pow(a.y,b), pow(a.z,b)); }

////////////////////////////////////////////////////////////////////////////////
/// Reduction Operators
////////////////////////////////////////////////////////////////////////////////

inline uniform float reduce_add(const uniform Vec3f a) { return a.x+a.y+a.z; }
inline varying float reduce_add(const varying Vec3f a) { return a.x+a.y+a.z; }

inline uniform float reduce_mul(const uniform Vec3f a) { return a.x*a.y*a.z; }
inline varying float reduce_mul(const varying Vec3f a) { return a.x*a.y*a.z; }

inline uniform float reduce_min(const uniform Vec3f a) { return min(min(a.x,a.y),a.z); }
inline varying float reduce_min(const varying Vec3f a) { return min(min(a.x,a.y),a.z); }

inline uniform float reduce_max(const uniform Vec3f a) { return max(max(a.x,a.y),a.z); }
inline varying float reduce_max(const varying Vec3f a) { return max(max(a.x,a.y),a.z); }

inline uniform Vec3f __reduce_min(const varying Vec3f a) { return make_Vec3f(reduce_min(a.x),reduce_min(a.y),reduce_min(a.z)); }
inline uniform Vec3f __reduce_max(const varying Vec3f a) { return make_Vec3f(reduce_max(a.x),reduce_max(a.y),reduce_max(a.z)); }

////////////////////////////////////////////////////////////////////////////////
/// Comparison Operators
////////////////////////////////////////////////////////////////////////////////

inline uniform bool eq(const uniform Vec3f a, const uniform Vec3f b) { return (a.x == b.x) & (a.y == b.y) & (a.z == b.z); }
inline varying bool eq(const varying Vec3f a, const varying Vec3f b) { return (a.x == b.x) & (a.y == b.y) & (a.z == b.z); }

inline uniform bool ne(const uniform Vec3f a, const uniform Vec3f b) { return (a.x != b.x) | (a.y != b.y) | (a.z != b.z); }
inline varying bool ne(const varying Vec3f a, const varying Vec3f b) { return (a.x != b.x) | (a.y != b.y) | (a.z != b.z); }

////////////////////////////////////////////////////////////////////////////////
/// Euclidian Space Operators
////////////////////////////////////////////////////////////////////////////////

inline uniform float dot(const uniform Vec3f a, const uniform Vec3f b) { return a.x*b.x+a.y*b.y+a.z*b.z; }
inline varying float dot(const varying Vec3f a, const varying Vec3f b) { return a.x*b.x+a.y*b.y+a.z*b.z; }

inline uniform float length(const uniform Vec3f a) { return sqrt(dot(a,a)); }
inline varying float length(const varying Vec3f a) { return sqrt(dot(a,a)); }

inline uniform Vec3f normalize(const uniform Vec3f a) { return rsqrt(dot(a,a))*a; }
inline varying Vec3f normalize(const varying Vec3f a) { return rsqrt(dot(a,a))*a; }

inline uniform float distance(const uniform Vec3f a, const uniform Vec3f b) { return length(a-b); }
inline varying float distance(const varying Vec3f a, const uniform Vec3f b) { return length(a-b); }

inline uniform Vec3f cross(const uniform Vec3f a, const uniform Vec3f b) { 
  return make_Vec3f(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}
inline varying Vec3f cross(const varying Vec3f a, const varying Vec3f b) { 
  return make_Vec3f(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}

inline uniform Vec3f lerp(const uniform float s, const uniform Vec3f v0, const uniform Vec3f v1) { return (1.0f-s)*v0+s*v1; }
inline varying Vec3f lerp(const varying float s, const varying Vec3f v0, const varying Vec3f v1) { return (1.0f-s)*v0+s*v1; }

inline uniform Vec3f reflect(const uniform Vec3f& V, const uniform Vec3f& N) { return 2.0f*dot(V,N)*N-V; }
inline varying Vec3f reflect(const uniform Vec3f& V, const varying Vec3f& N) { return 2.0f*dot(V,N)*N-V; }
inline varying Vec3f reflect(const varying Vec3f& V, const uniform Vec3f& N) { return 2.0f*dot(V,N)*N-V; }
inline varying Vec3f reflect(const varying Vec3f& V, const varying Vec3f& N) { return 2.0f*dot(V,N)*N-V; }
