import ctypes
from gl2_constants import *

_gl = ctypes.CDLL('libGLESv2.so')


GLboolean = ctypes.c_ubyte
GLint = ctypes.c_int
GLsizei = ctypes.c_int
GLuint = ctypes.c_uint
GLshort = ctypes.c_short
GLfloat = ctypes.c_float
GLdouble = ctypes.c_double

GL_FALSE = GLboolean(0)
GL_TRUE = GLboolean(1)


def GLints(L):
	"""Converts a tuple to an array of GLints (would a pointer return be better?)"""
	return (GLint * len(L))(*L)


def GLshorts(L):
	"""Converts a tuple to an array of GLshorts (would a pointer return be better?)"""
	return (GLshort * len(L))(*L)


def GLfloats(L):
	return (GLfloat * len(L))(*L)


def glGenBuffers(n):
	buffers = ctypes.c_uint()
	_gl.glGenBuffers(n, ctypes.byref(buffers))
	return buffers


def glBufferData(target, data, usage):
	_gl.glBufferData(target, ctypes.sizeof(data), ctypes.byref(data), usage)


def glShaderSource(shader_obj, string):
	_gl.glShaderSource(shader_obj, 1, ctypes.byref(ctypes.c_char_p(string)), 0)


def glBindAttribLocation(program, index, name):
	_gl.glBindAttribLocation(program, index, ctypes.byref(ctypes.c_char_p(name)))


def glUniformMatrix4fv(location, count, transpose, value):
	_gl.glUniformMatrix4fv(location, count, transpose, ctypes.byref(value))


def glUniform1i(location, value):
	_gl.glUniform1i(location, GLint(value))


def glUniform1f(location, value):
	_gl.glUniform1f(location, GLfloat(value))


def glUniform2f(location, v0, v1):
	_gl.glUniform2f(location, GLfloat(v0), GLfloat(v1))


def glGetShaderInfoLog(shader):
	N = 1024
	log = (ctypes.c_char * N)()
	loglen = ctypes.c_int()
	_gl.glGetShaderInfoLog(shader, N, ctypes.byref(loglen), ctypes.byref(log))
	return log.value


def glGetProgramInfoLog(program):
	N = 1024
	log = (ctypes.c_char * N)()
	loglen = ctypes.c_int()
	_gl.glGetProgramInfoLog(program, N, ctypes.byref(loglen), ctypes.byref(log))
	return log.value


def glDepthRangef(n, f):
	_gl.glDepthRangef(GLfloat(n), GLfloat(f))


def glClearColor(r, g, b, a):
	_gl.glClearColor(GLfloat(r), GLfloat(g), GLfloat(b), GLfloat(a))


def glGetShaderiv(shader, pname):
	status = GLint()
	_gl.glGetShaderiv(shader, pname, ctypes.byref(status))
	return status.value


def glGetProgramiv(program, pname):
	raise Exception("FIXME: glGetProgramiv is broken")
	params = GLint()
	_gl.glGetShaderiv(GLuint(program), pname, ctypes.byref(params))
	return params.value


def glGenTextures(n):
	textures = ctypes.c_uint()
	_gl.glGenTextures(n, ctypes.byref(textures))
	if n == 1:
		return textures.value
	else:
		raise Exception("glGenTextures with n > 1 not implemented yet")


def glTexImage2D(target, level, internalformat, width, height, border, format, typ, pixels):
	_gl.glTexImage2D(target, GLint(level), GLint(internalformat), GLsizei(width), GLsizei(height), GLint(border), format, typ, ctypes.c_char_p(pixels))


def glBindTexture(target, texture):
	_gl.glBindTexture(target, GLuint(texture))


def glCreateProgram():
	return long(_gl.glCreateProgram())


def glLinkProgram(program):
	_gl.glLinkProgram(GLuint(program))


def glValidateProgram(program):
	_gl.glValidateProgram(GLuint(program))


glBindBuffer = _gl.glBindBuffer
glVertexAttribPointer = _gl.glVertexAttribPointer
glEnableVertexAttribArray = _gl.glEnableVertexAttribArray
glDrawElements = _gl.glDrawElements
glCreateShader = _gl.glCreateShader
glCompileShader = _gl.glCompileShader
glAttachShader = _gl.glAttachShader
glUseProgram = _gl.glUseProgram
glGetAttribLocation = _gl.glGetAttribLocation
glGetUniformLocation = _gl.glGetUniformLocation
glViewport = _gl.glViewport
glBindFramebuffer = _gl.glBindFramebuffer
glFrontFace = _gl.glFrontFace
glCullFace = _gl.glCullFace
glEnable = _gl.glEnable
glClear = _gl.glClear
glFinish = _gl.glFinish
glGetError = _gl.glGetError
glDrawArrays = _gl.glDrawArrays
glPixelStorei = _gl.glPixelStorei
glTexParameteri = _gl.glTexParameteri
glActiveTexture = _gl.glActiveTexture
glBlendFunc = _gl.glBlendFunc


def check_gl_error():
	err = glGetError()
	if err:
		raise ValueError(err)
