// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.

#ifndef tools_glprims
#define tools_glprims

//same as OpenGL GL_[POINTS,etc...], but for the case we don't have OpenGL.

#include <cstddef> //size_t

namespace tools {
namespace gl {

typedef unsigned char mode_t;

inline mode_t points()         {return 0x0000;}
inline mode_t lines()          {return 0x0001;} //segments
inline mode_t line_loop()      {return 0x0002;}
inline mode_t line_strip()     {return 0x0003;} //polyline
inline mode_t triangles()      {return 0x0004;}
inline mode_t triangle_strip() {return 0x0005;}
inline mode_t triangle_fan()   {return 0x0006;}

inline bool is_mode(mode_t a_mode) {
  return a_mode<=0x006?true:false;
}

inline bool is_line(mode_t a_mode) {
  if(a_mode==points())     return true; //0 sz line !
  if(a_mode==lines())      return true;
  if(a_mode==line_loop())  return true;
  if(a_mode==line_strip()) return true;
  return false;
}

inline void cvt_2to3(size_t a_npt,const float* a_xys,float*& a_xyzs) {
  const float* vpos = a_xys;
  float x,y;
  for(size_t i=0;i<a_npt;i++) {
    x = *vpos;vpos++;
    y = *vpos;vpos++;
    *a_xyzs = x;a_xyzs++;
    *a_xyzs = y;a_xyzs++;
    *a_xyzs = 0;a_xyzs++;
  }
}


inline void triangle_fan_to_triangles(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
  // a_pxyzs = (a_npt-2)*3*3

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;
  float z1 = *vpos;vpos++;

  float x2 = *vpos;vpos++;
  float y2 = *vpos;vpos++;
  float z2 = *vpos;vpos++;

  float x3,y3,z3;
  for(size_t i=2;i<a_npt;i++) {
    x3 = *vpos;vpos++;
    y3 = *vpos;vpos++;
    z3 = *vpos;vpos++;
    *a_pxyzs = x1;a_pxyzs++;
    *a_pxyzs = y1;a_pxyzs++;
    *a_pxyzs = z1;a_pxyzs++;

    *a_pxyzs = x2;a_pxyzs++;
    *a_pxyzs = y2;a_pxyzs++;
    *a_pxyzs = z2;a_pxyzs++;

    *a_pxyzs = x3;a_pxyzs++;
    *a_pxyzs = y3;a_pxyzs++;
    *a_pxyzs = z3;a_pxyzs++;

    x2 = x3;
    y2 = y3;
    z2 = z3;
  }

}

inline void triangle_fan_to_triangles_texture(size_t a_npt,const float* a_xyzs,const float* a_tcs,float*& a_pxyzs,float*& a_ptcs) {
  // a_pxyzs = (a_npt-2)*3*3

  // a_ptcs = (a_npt-2)*3*2

  const float* vpos = a_xyzs;
  const float* tpos = a_tcs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;
  float z1 = *vpos;vpos++;

  float tx1 = *tpos;tpos++;
  float ty1 = *tpos;tpos++;

  float x2 = *vpos;vpos++;
  float y2 = *vpos;vpos++;
  float z2 = *vpos;vpos++;

  float tx2 = *tpos;tpos++;
  float ty2 = *tpos;tpos++;
  
  float x3,y3,z3,tx3,ty3;
  for(size_t i=2;i<a_npt;i++) {
    x3 = *vpos;vpos++;
    y3 = *vpos;vpos++;
    z3 = *vpos;vpos++;

    tx3 = *tpos;tpos++;
    ty3 = *tpos;tpos++;
    
    *a_pxyzs = x1;a_pxyzs++;
    *a_pxyzs = y1;a_pxyzs++;
    *a_pxyzs = z1;a_pxyzs++;

    *a_ptcs = tx1;a_ptcs++;
    *a_ptcs = ty1;a_ptcs++;

    *a_pxyzs = x2;a_pxyzs++;
    *a_pxyzs = y2;a_pxyzs++;
    *a_pxyzs = z2;a_pxyzs++;

    *a_ptcs = tx2;a_ptcs++;
    *a_ptcs = ty2;a_ptcs++;
    
    *a_pxyzs = x3;a_pxyzs++;
    *a_pxyzs = y3;a_pxyzs++;
    *a_pxyzs = z3;a_pxyzs++;

    *a_ptcs = tx3;a_ptcs++;
    *a_ptcs = ty3;a_ptcs++;
    
    x2 = x3;
    y2 = y3;
    z2 = z3;

    tx2 = tx3;
    ty2 = ty3;
  }

}

inline void triangle_strip_to_triangles(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
  // a_pxyzs = (a_npt-2)*3*3

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;
  float z1 = *vpos;vpos++;

  float x2 = *vpos;vpos++;
  float y2 = *vpos;vpos++;
  float z2 = *vpos;vpos++;

  float x3,y3,z3;
  bool flip = false;
  for(size_t i=2;i<a_npt;i++) {
    x3 = *vpos;vpos++;
    y3 = *vpos;vpos++;
    z3 = *vpos;vpos++;

    if(flip) {
      *a_pxyzs = x1;a_pxyzs++;
      *a_pxyzs = y1;a_pxyzs++;
      *a_pxyzs = z1;a_pxyzs++;

      *a_pxyzs = x3;a_pxyzs++;
      *a_pxyzs = y3;a_pxyzs++;
      *a_pxyzs = z3;a_pxyzs++;

      *a_pxyzs = x2;a_pxyzs++;
      *a_pxyzs = y2;a_pxyzs++;
      *a_pxyzs = z2;a_pxyzs++;
    } else {
      *a_pxyzs = x1;a_pxyzs++;
      *a_pxyzs = y1;a_pxyzs++;
      *a_pxyzs = z1;a_pxyzs++;

      *a_pxyzs = x2;a_pxyzs++;
      *a_pxyzs = y2;a_pxyzs++;
      *a_pxyzs = z2;a_pxyzs++;

      *a_pxyzs = x3;a_pxyzs++;
      *a_pxyzs = y3;a_pxyzs++;
      *a_pxyzs = z3;a_pxyzs++;
    }

    x1 = x2;
    y1 = y2;
    z1 = z2;

    x2 = x3;
    y2 = y3;
    z2 = z3;

    flip = flip?false:true;
  }
}

inline void triangle_strip_to_triangles_texture(size_t a_npt,const float* a_xyzs,const float* a_tcs,float*& a_pxyzs,float*& a_ptcs) {
  // a_pxyzs = (a_npt-2)*3*3
  // a_ptcs = (a_npt-2)*3*2

  const float* vpos = a_xyzs;
  const float* tpos = a_tcs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;
  float z1 = *vpos;vpos++;

  float tx1 = *tpos;tpos++;
  float ty1 = *tpos;tpos++;
  
  float x2 = *vpos;vpos++;
  float y2 = *vpos;vpos++;
  float z2 = *vpos;vpos++;

  float tx2 = *tpos;tpos++;
  float ty2 = *tpos;tpos++;
  
  float x3,y3,z3,tx3,ty3;
  bool flip = false;
  for(size_t i=2;i<a_npt;i++) {
    x3 = *vpos;vpos++;
    y3 = *vpos;vpos++;
    z3 = *vpos;vpos++;

    tx3 = *tpos;tpos++;
    ty3 = *tpos;tpos++;
  
    if(flip) {
      *a_pxyzs = x1;a_pxyzs++;
      *a_pxyzs = y1;a_pxyzs++;
      *a_pxyzs = z1;a_pxyzs++;

      *a_ptcs = tx1;a_ptcs++;
      *a_ptcs = ty1;a_ptcs++;
      
      *a_pxyzs = x3;a_pxyzs++;
      *a_pxyzs = y3;a_pxyzs++;
      *a_pxyzs = z3;a_pxyzs++;

      *a_ptcs = tx3;a_ptcs++;
      *a_ptcs = ty3;a_ptcs++;
      
      *a_pxyzs = x2;a_pxyzs++;
      *a_pxyzs = y2;a_pxyzs++;
      *a_pxyzs = z2;a_pxyzs++;

      *a_ptcs = tx2;a_ptcs++;
      *a_ptcs = ty2;a_ptcs++;
    } else {
      *a_pxyzs = x1;a_pxyzs++;
      *a_pxyzs = y1;a_pxyzs++;
      *a_pxyzs = z1;a_pxyzs++;

      *a_ptcs = tx1;a_ptcs++;
      *a_ptcs = ty1;a_ptcs++;
      
      *a_pxyzs = x2;a_pxyzs++;
      *a_pxyzs = y2;a_pxyzs++;
      *a_pxyzs = z2;a_pxyzs++;

      *a_ptcs = tx2;a_ptcs++;
      *a_ptcs = ty2;a_ptcs++;
      
      *a_pxyzs = x3;a_pxyzs++;
      *a_pxyzs = y3;a_pxyzs++;
      *a_pxyzs = z3;a_pxyzs++;
      
      *a_ptcs = tx3;a_ptcs++;
      *a_ptcs = ty3;a_ptcs++;
    }

    x1 = x2;
    y1 = y2;
    z1 = z2;

    tx1 = tx2;
    ty1 = ty2;

    x2 = x3;
    y2 = y3;
    z2 = z3;

    tx2 = tx3;
    ty2 = ty3;
    
    flip = flip?false:true;
  }
}

inline void triangle_fan_to_triangles_nms(size_t a_npt,const float* a_xyzs,const float* a_nms,float*& a_pxyzs,float*& a_pnms) {
  triangle_fan_to_triangles(a_npt,a_xyzs,a_pxyzs);
  triangle_fan_to_triangles(a_npt,a_nms,a_pnms);
}

inline void triangle_strip_to_triangles_nms(size_t a_npt,const float* a_xyzs,const float* a_nms,float*& a_pxyzs,float*& a_pnms) {
  // a_pxyzs, a_pnms = (a_npt-2)*3*3
  triangle_strip_to_triangles(a_npt,a_xyzs,a_pxyzs);
  triangle_strip_to_triangles(a_npt,a_nms,a_pnms);
}

inline void triangle_fan_to_triangles_2to3(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;

  float x2 = *vpos;vpos++;
  float y2 = *vpos;vpos++;

  float x3,y3;
  for(size_t i=2;i<a_npt;i++) {
    x3 = *vpos;vpos++;
    y3 = *vpos;vpos++;

    *a_pxyzs = x1;a_pxyzs++;
    *a_pxyzs = y1;a_pxyzs++;
    *a_pxyzs = 0;a_pxyzs++;

    *a_pxyzs = x2;a_pxyzs++;
    *a_pxyzs = y2;a_pxyzs++;
    *a_pxyzs = 0;a_pxyzs++;

    *a_pxyzs = x3;a_pxyzs++;
    *a_pxyzs = y3;a_pxyzs++;
    *a_pxyzs = 0;a_pxyzs++;

    x2 = x3;
    y2 = y3;
  }

}

inline void triangle_strip_to_triangles_2to3(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;

  float x2 = *vpos;vpos++;
  float y2 = *vpos;vpos++;

  float x3,y3;
  bool flip = false;
  for(size_t i=2;i<a_npt;i++) {
    x3 = *vpos;vpos++;
    y3 = *vpos;vpos++;

    if(flip) {
      *a_pxyzs = x1;a_pxyzs++;
      *a_pxyzs = y1;a_pxyzs++;
      *a_pxyzs = 0;a_pxyzs++;

      *a_pxyzs = x3;a_pxyzs++;
      *a_pxyzs = y3;a_pxyzs++;
      *a_pxyzs = 0;a_pxyzs++;

      *a_pxyzs = x2;a_pxyzs++;
      *a_pxyzs = y2;a_pxyzs++;
      *a_pxyzs = 0;a_pxyzs++;
    } else {
      *a_pxyzs = x1;a_pxyzs++;
      *a_pxyzs = y1;a_pxyzs++;
      *a_pxyzs = 0;a_pxyzs++;

      *a_pxyzs = x2;a_pxyzs++;
      *a_pxyzs = y2;a_pxyzs++;
      *a_pxyzs = 0;a_pxyzs++;

      *a_pxyzs = x3;a_pxyzs++;
      *a_pxyzs = y3;a_pxyzs++;
      *a_pxyzs = 0;a_pxyzs++;
    }

    x1 = x2;
    y1 = y2;

    x2 = x3;
    y2 = y3;

    flip = flip?false:true;
  }

}

inline void line_strip_to_lines_2to3(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;

  float x2,y2;
  for(size_t i=1;i<a_npt;i++) {
    x2 = *vpos;vpos++;
    y2 = *vpos;vpos++;

    *a_pxyzs = x1;a_pxyzs++;
    *a_pxyzs = y1;a_pxyzs++;
    *a_pxyzs = 0;a_pxyzs++;

    *a_pxyzs = x2;a_pxyzs++;
    *a_pxyzs = y2;a_pxyzs++;
    *a_pxyzs = 0;a_pxyzs++;

    x1 = x2;
    y1 = y2;
  }

}

inline void line_strip_to_lines(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
  // a_pxyzs = (a_npt-1)*2*3

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;
  float z1 = *vpos;vpos++;

  float x2,y2,z2;
  for(size_t i=1;i<a_npt;i++) {
    x2 = *vpos;vpos++;
    y2 = *vpos;vpos++;
    z2 = *vpos;vpos++;

    *a_pxyzs = x1;a_pxyzs++;
    *a_pxyzs = y1;a_pxyzs++;
    *a_pxyzs = z1;a_pxyzs++;

    *a_pxyzs = x2;a_pxyzs++;
    *a_pxyzs = y2;a_pxyzs++;
    *a_pxyzs = z2;a_pxyzs++;

    x1 = x2;
    y1 = y2;
    z1 = z2;
  }

}

inline void line_loop_to_lines(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
  // a_pxyzs = a_npt*2*3

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;
  float z1 = *vpos;vpos++;

  float x0 = x1;
  float y0 = y1;
  float z0 = z1;

  float x2,y2,z2;
  for(size_t i=1;i<a_npt;i++) {
    x2 = *vpos;vpos++;
    y2 = *vpos;vpos++;
    z2 = *vpos;vpos++;

    *a_pxyzs = x1;a_pxyzs++;
    *a_pxyzs = y1;a_pxyzs++;
    *a_pxyzs = z1;a_pxyzs++;

    *a_pxyzs = x2;a_pxyzs++;
    *a_pxyzs = y2;a_pxyzs++;
    *a_pxyzs = z2;a_pxyzs++;

    x1 = x2;
    y1 = y2;
    z1 = z2;
  }

  *a_pxyzs = x1;a_pxyzs++;
  *a_pxyzs = y1;a_pxyzs++;
  *a_pxyzs = z1;a_pxyzs++;

  *a_pxyzs = x0;a_pxyzs++;
  *a_pxyzs = y0;a_pxyzs++;
  *a_pxyzs = z0;a_pxyzs++;

}

inline void line_loop_to_line_strip(size_t a_npt,const float* a_xyzs,float*& a_pxyzs) {
  // a_pxyzs = (a_npt+1)*3

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;
  float z1 = *vpos;vpos++;

  for(size_t i=0;i<a_npt;i++) {
    *a_pxyzs = *vpos;vpos++;a_pxyzs++;
    *a_pxyzs = *vpos;vpos++;a_pxyzs++;
    *a_pxyzs = *vpos;vpos++;a_pxyzs++;
  }

  *a_pxyzs = x1;a_pxyzs++;
  *a_pxyzs = y1;a_pxyzs++;
  *a_pxyzs = z1;a_pxyzs++;
}

/// for DirectX_action :
inline void triangle_fan_to_triangles_2to3(size_t a_npt,const float* a_xyzs,
                                           float a_r,float a_g,float a_b,float a_a,
					   float*& a_pxyz_rgbas) {

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;

  float x2 = *vpos;vpos++;
  float y2 = *vpos;vpos++;

  float x3,y3;
  for(size_t i=2;i<a_npt;i++) {
    x3 = *vpos;vpos++;
    y3 = *vpos;vpos++;

    *a_pxyz_rgbas = x1;a_pxyz_rgbas++;
    *a_pxyz_rgbas = y1;a_pxyz_rgbas++;
    *a_pxyz_rgbas = 0;a_pxyz_rgbas++;

    *a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_a;a_pxyz_rgbas++;

    *a_pxyz_rgbas = x2;a_pxyz_rgbas++;
    *a_pxyz_rgbas = y2;a_pxyz_rgbas++;
    *a_pxyz_rgbas = 0;a_pxyz_rgbas++;

    *a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_a;a_pxyz_rgbas++;

    *a_pxyz_rgbas = x3;a_pxyz_rgbas++;
    *a_pxyz_rgbas = y3;a_pxyz_rgbas++;
    *a_pxyz_rgbas = 0;a_pxyz_rgbas++;

    *a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_a;a_pxyz_rgbas++;

    x2 = x3;
    y2 = y3;
  }
}

inline void triangle_fan_to_triangles(size_t a_npt,const float* a_xyzs,
                                      float a_r,float a_g,float a_b,float a_a,
				      float*& a_pxyz_rgbas) {

  const float* vpos = a_xyzs;

  float x1 = *vpos;vpos++;
  float y1 = *vpos;vpos++;
  float z1 = *vpos;vpos++;

  float x2 = *vpos;vpos++;
  float y2 = *vpos;vpos++;
  float z2 = *vpos;vpos++;

  float x3,y3,z3;
  for(size_t i=2;i<a_npt;i++) {
    x3 = *vpos;vpos++;
    y3 = *vpos;vpos++;
    z3 = *vpos;vpos++;

    *a_pxyz_rgbas = x1;a_pxyz_rgbas++;
    *a_pxyz_rgbas = y1;a_pxyz_rgbas++;
    *a_pxyz_rgbas = z1;a_pxyz_rgbas++;

    *a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_a;a_pxyz_rgbas++;

    *a_pxyz_rgbas = x2;a_pxyz_rgbas++;
    *a_pxyz_rgbas = y2;a_pxyz_rgbas++;
    *a_pxyz_rgbas = z2;a_pxyz_rgbas++;

    *a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_a;a_pxyz_rgbas++;

    *a_pxyz_rgbas = x3;a_pxyz_rgbas++;
    *a_pxyz_rgbas = y3;a_pxyz_rgbas++;
    *a_pxyz_rgbas = z3;a_pxyz_rgbas++;

    *a_pxyz_rgbas = a_r;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_g;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_b;a_pxyz_rgbas++;
    *a_pxyz_rgbas = a_a;a_pxyz_rgbas++;

    x2 = x3;
    y2 = y3;
    z2 = z3;
  }
}

}}

#endif
