
struct ParamList
{
  int m_func;
  std::vector<int> int_params;
  std::vector<void*> void_params;
};

class OpenglLowApi_thread : public OpenglLowApi
{
public:
  OpenglLowApi_thread(OpenglLowApi *next) : next(next) { }
  virtual void init()
  {
  }
  virtual void cleanup()
  {
  }

  virtual int glGetError()
  {
    return 0;
  }
  
  virtual void glColor4ub(int r, int g, int b, int a)
  {
    if (is_thread()) {
      lock(true);
      clear_param();
      set_func(1);
      push_param_i(0,r);
      push_param_i(1,g);
      push_param_i(2,b);
      push_param_i(3,a);
      execute();
      lock(false);
    } else
      {
	next->glColor4ub(r,g,b,a);
      }
  }
  virtual void glColor4f(float r, float g, float b, float a)
  {
    if (is_thread()) {
      lock(true);
      clear_param();
      set_func(2);
      push_param_f(0,r);
      push_param_f(1,g);
      push_param_f(2,b);
      push_param_f(3,a);
      execute();
      lock(false);
    } else
      {
	next->glColor4f(r,g,b,a);
      }
  }
  virtual void glClearColor(float r, float g, float b, float a)=0;
  virtual void glClear(int bits)=0;
  virtual void glDepthMask(int a)=0;
  virtual void glDepthFunc(int i)=0;
  virtual void glStencilMask(int a)=0;
  virtual void glStencilOp(int keep, int keep2, int repl)=0;
  virtual void glStencilFunc(int notequal, int, int)=0;
  virtual void glPolygonMode(int front_and_back, int gl_line)=0;
  virtual void glClearStencil(int val)=0;
  virtual void glTexEnvi(int a, int mode, int rep)=0;

  // attribs
  virtual void glEnable(int val)=0;
  virtual void glDisable(int val)=0;
  virtual void glGetFloatv(int val, float *params)=0;

  // viewports
  virtual void glViewport(int x, int y, unsigned int w, unsigned int h)=0;

  // textures
  virtual void glGenTextures(int val, unsigned int *tex)=0;
  virtual void glDeleteTextures(int val, const unsigned int *tex)=0;
  virtual void glBindTexture(int ID, int tex)=0;
  virtual void glTexImage2D(int ID, int, int,unsigned int,unsigned int, int, int, int, void *ptr)=0;
  virtual void glTexSubImage2D(int ID, int,int,int,unsigned int, unsigned int, int,int, void *ptr)=0;
  virtual void glCopyTexImage2D(int ID, int,int,int,int, int,int, int ptr)=0;
  virtual void glTexParameteri(int ID, int,int)=0;
  virtual void glHint(int hint, int value)=0;
  virtual void glActiveTexture(int a)=0;
  virtual void glClientActiveTexture(int a)=0;
  virtual void glTexStorage3D(int arr, int, int flag, int w, int h, int layer_count)=0;
  virtual void glTexSubImage3D(int arr, int,int,int,int,int,int, int, int rgba, int unsig_byte, void *buffer)=0;
  virtual void glGetTexLevelParameteriv(int a, int, int w, int *ptr)=0;
  virtual void glGetTexImage(int a, int, int rgba, int unsign_byte, void *ptr)=0;
  virtual void glReadBuffer(int a)=0;
  

  // blend
  virtual void glBlendFunc(int val, int val2)=0;
  
  // scissor
  virtual void glScissor(float x, float y, float w, float h)=0;

  // fbo
  //virtual void glGenRenderbuffers(int i, unsigned int *ptr)=0;
  virtual void glFramebufferTexture2D(int i, int atth, int tex2d, int tex, int ptr)=0;

  // vertex arrays
  virtual void glGenBuffers(int i, unsigned int *buffers)=0;
  virtual void glDeleteBuffers(int count, const unsigned int *buffers)=0;
  virtual void glBindBuffer(int a, unsigned int data)=0;
  virtual void glBufferData(int a, int size, const void *ptr, int static_draw)=0;
  virtual void glBufferSubData(int a, int, int, const void*)=0;
  virtual void glVertexAttribPointer(int, int, int gl_float, int boolean, unsigned int, const void *ptr)=0;
  virtual void glVertexAttribIPointer(int, int, int gl_float, int boolean, const void *ptr)=0;
  virtual void glVertexAttribDivisor(int, int)=0;
  virtual void glGenVertexArrays(int i, unsigned int *arr)=0;
  virtual void glDeleteVertexArrays(int count, unsigned int *vao)=0;
  virtual void glBindVertexArray(int vao)=0;
  virtual void glEnableVertexAttribArray(int a)=0;
  virtual void glDisableVertexAttribArray(int a)=0;
  virtual void glDrawArraysInstanced(int tri, int, unsigned int, unsigned int)=0;
  virtual void glDrawArrays(int tri, int, unsigned int)=0;
  
  // bitmaps
  virtual void glReadPixels(int x, int y, int w, int h, int rgba, int mode, void *ptr)=0;
  
  // fbo
  virtual void glGenFramebuffers(int i, unsigned int *fbo_id)=0;
  virtual void glGenRenderbuffers(int i, unsigned int *rbo_id)=0;
  virtual void glDeleteRenderBuffers(int i, unsigned int *rbo)=0;
  virtual void glDeleteFrameBuffers(int i, unsigned int *fbo)=0;
  virtual void glBindFramebuffer(int a, int fbo_id)=0;
  virtual void glBindRenderbuffer(int a, int fbo_id)=0;
  virtual void glRenderbufferStorage(int a, int d, int sx, int sy)=0;
  virtual void glFramebufferRenderbuffer(int a, int d, int r, unsigned int tex)=0;
  
  // shaders
  virtual unsigned int glCreateShader(int shader)=0;
  virtual void glShaderSource(int h, int c, const char **strings, int *lengths)=0;
  virtual void glCompileShader(int h)=0;
  virtual void glGetShaderInfoLog(unsigned int h, int val, int *length, char *buf)=0;
  virtual void glGetShaderiv(int handle, int gl_compile_status, int *ptr)=0;
  virtual void glDeleteShader(int h)=0;
  
  // programs
  virtual int glCreateProgram()=0;
  virtual void glDeleteProgram(int p)=0;
 virtual  void glAttachShader(int p, int h)=0; 
  virtual void glDetachShader(int p, int h)=0;
  virtual void glLinkProgram(int p)=0;
  virtual void glUseProgram(int p)=0;
  virtual void glGetProgramInfoLog(unsigned int p, int num, int *len, char *buf)=0;
  virtual void glBindFragDataLocation(int p, int num, const char *data)=0;
  virtual void glBindAttribLocation(int p, int num, const char *data)=0;
  virtual void glProgramParameteriEXT(int p, int geom, int inputtype)=0;
  
  // uniforms
  virtual int glGetUniformLocation(int p, const char *data)=0;
  virtual int glGetAttribLocation(int p, const char *data)=0;
  virtual void glUniform1f(int loc, float val)=0;
  virtual void glUniform1i(int loc, int val)=0;
  virtual void glUniform2f(int loc, float val, float val2)=0;
  virtual void glUniform3f(int loc, float val, float val2, float val3)=0;
  virtual void glUniform4f(int loc, float val, float val2, float val3, float val4)=0;
  virtual void glUniform1iv(int loc, int count, int *array)=0;
  virtual void glUniform1fv(int loc, int count, float *array)=0;
  virtual void glUniformMatrix4fv(int loc, unsigned int count, int boolean, const float *matrix)=0;
  virtual void glUniform3fv(int loc, int count, float *arr)=0;
  virtual void glGetUniformfv(int p, int loc, float *arr)=0;
  virtual void glGetIntegerv(int p, int *ptr)=0;
  virtual int glCheckFramebufferStatus(int id)=0;

  virtual void glFinish()=0;

  virtual const unsigned char *glGetString( int name )=0;
  virtual void glGenerateMipmap(int p)=0;

  // Old
  virtual void glEnableClientState(int a)=0;
  virtual void glLineWidth(float i)=0;
  virtual void glPushMatrix()=0;
  virtual void glPopMatrix()=0;
  virtual void glMultMatrixf(float *mat)=0;
  virtual void glMatrixLoadIdentityEXT(int i)=0;
  virtual void glMatrixMode(int i)=0;
  virtual void glLoadIdentity()=0;
  virtual void glTranslatef(float, float, float)=0;
  virtual void glDisableClientState(int) { }
  virtual void glTexCoordPointer(int,int,int, void*) { }
  virtual void glColorPointer(int,int,int,void*) { }
  virtual void glVertexPointer(int,int,int,void*) { }
  virtual void glNormalPointer(int,int,void*) { }
  virtual void glRotatef(float,float,float,float) {}
  //virtual void glEnableClientState(int) { }
  //virtual void glDisableClientState(int) { }
  virtual void glColor3f(float,float,float) { }
  virtual void glCallList(int) { }
  virtual void glEndList() { }
  virtual void glEnd() { }
  virtual void glVertex3f(float,float,float) { }
  virtual void glNormal3f(float,float,float) { }
  virtual void glTexCoord2f(float,float) { }
  virtual void glVertexAttrib1s(int loc, short s) {}
  virtual void glVertexAttrib1f(int loc, float s) {}
  virtual void glBegin(int) { }
  virtual void glNewList(int i, int k) { }
  virtual int glGenLists(int) { return 0; }
  virtual void glDeleteLists(int,int) {}
private:
  void lock(bool lock) { }
  bool is_thread() const { }
  void clear_param() { }
  void set_func(int func) { }
  void push_param_i(int i, int val) { }
  void push_param_v(int i, void *val) { }
  void push_param_f(int i, float val) { }
  void execute() { }
private:
  OpenglLowApi *next;
  ParamList curr;
};
