#include "bind_vertex_attrib_array.h"

namespace igl{ namespace opengl{
// This would be cleaner with C++17 if constexpr
template <typename Scalar>
IGL_INLINE void bind_vertex_attrib_array_helper(
  const GLint id, 
  const int size, 
  const int num_cols, 
  const Scalar * data, 
  const bool refresh);

template <>
IGL_INLINE void bind_vertex_attrib_array_helper<float>(
  const GLint id, 
  const int size, 
  const int num_cols, 
  const float * data, 
  const bool refresh)
{
  if (refresh)
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*size, data, GL_DYNAMIC_DRAW);
  glVertexAttribPointer(id, num_cols, GL_FLOAT, GL_FALSE, 0, 0);
};

template <>
IGL_INLINE void bind_vertex_attrib_array_helper<double>(
  const GLint id, 
  const int size, 
  const int num_cols, 
  const double * data, 
  const bool refresh)
{
  // Are you really sure you want to use doubles? Are you going to change the
  // `in vec3` etc. in your vertex shader to `in dvec3` ?
  // Are you on a mac, where this will be emulated in software?
  if (refresh)
    glBufferData(GL_ARRAY_BUFFER, sizeof(double)*size, data, GL_DYNAMIC_DRAW);
  glVertexAttribLPointer(id, num_cols, GL_DOUBLE, 0, 0);
};
}}


namespace igl{ namespace opengl{
template <typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
IGL_INLINE GLint bind_vertex_attrib_array(
  const GLuint program_shader,
  const std::string &name, 
  GLuint bufferID, 
  const Eigen::Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime,Eigen::RowMajor> &M,
  const bool refresh)
{
  GLint id = glGetAttribLocation(program_shader, name.c_str());
  if (id < 0)
    return id;
  if (M.size() == 0)
  {
    glDisableVertexAttribArray(id);
    return id;
  }
  glBindBuffer(GL_ARRAY_BUFFER, bufferID);

  bind_vertex_attrib_array_helper<Scalar>(
    id, M.size(), M.cols(), M.data(), refresh);

  glEnableVertexAttribArray(id);
  return id;
}
}}

#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
// generated by autoexplicit.sh
template int igl::opengl::bind_vertex_attrib_array<float, -1, -1>(unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int, Eigen::Matrix<float, -1, -1, 1, -1, -1> const&, bool);
// generated by autoexplicit.sh
template int igl::opengl::bind_vertex_attrib_array<float, -1, 3>(unsigned int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int, Eigen::Matrix<float, -1, 3, 1, -1, 3> const&, bool);
#endif
