#pragma once

// GL type and enum definitions only -- GL_GLEXT_PROTOTYPES stays undefined here so that
// nothing outside the generated GLFunctions implementation can call GL directly.
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
extern "C" {
#include <GLES2/gl2ext_angle.h>
}
#include <GLES3/gl3.h>

#include <LibWeb/WebGL/Types.h>

namespace Web::WebGL {

class GLFunctions {
public:
    void active_texture(GLenum texture);
    void attach_shader(GLuint program, GLuint shader);
    void begin_query(GLenum target, GLuint id);
    void begin_transform_feedback(GLenum primitiveMode);
    void bind_attrib_location(GLuint program, GLuint index, GLchar const* name);
    void bind_buffer(GLenum target, GLuint buffer);
    void bind_buffer_base(GLenum target, GLuint index, GLuint buffer);
    void bind_buffer_range(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
    void bind_framebuffer(GLenum target, GLuint framebuffer);
    void bind_renderbuffer(GLenum target, GLuint renderbuffer);
    void bind_sampler(GLuint unit, GLuint sampler);
    void bind_texture(GLenum target, GLuint texture);
    void bind_transform_feedback(GLenum target, GLuint id);
    void bind_vertex_array(GLuint array);
    void bind_vertex_array_oes(GLuint array);
    void blend_color(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
    void blend_equation(GLenum mode);
    void blend_equation_separate(GLenum modeRGB, GLenum modeAlpha);
    void blend_func(GLenum sfactor, GLenum dfactor);
    void blend_func_separate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
    void blit_framebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
    void buffer_data(GLenum target, GLsizeiptr size, void const* data, GLenum usage);
    void buffer_sub_data(GLenum target, GLintptr offset, GLsizeiptr size, void const* data);
    GLenum check_framebuffer_status(GLenum target);
    void clear(GLbitfield mask);
    void clear_bufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
    void clear_bufferfv(GLenum buffer, GLint drawbuffer, GLfloat const* value);
    void clear_bufferiv(GLenum buffer, GLint drawbuffer, GLint const* value);
    void clear_bufferuiv(GLenum buffer, GLint drawbuffer, GLuint const* value);
    void clear_color(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
    void clear_depthf(GLfloat d);
    void clear_stencil(GLint s);
    GLenum client_wait_sync(GLsync sync, GLbitfield flags, GLuint64 timeout);
    void color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
    void compile_shader(GLuint shader);
    void compressed_tex_image2d_robust_angle(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLsizei bufSize, void const* data);
    void compressed_tex_image3d_robust_angle(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLsizei bufSize, void const* data);
    void compressed_tex_sub_image2d_robust_angle(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLsizei bufSize, void const* data);
    void compressed_tex_sub_image3d_robust_angle(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLsizei bufSize, void const* data);
    void copy_buffer_sub_data(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
    void copy_tex_image2d(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
    void copy_tex_sub_image2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
    GLuint create_program();
    GLuint create_shader(GLenum type);
    void cull_face(GLenum mode);
    void delete_buffers(GLsizei n, GLuint const* buffers);
    void delete_framebuffers(GLsizei n, GLuint const* framebuffers);
    void delete_program(GLuint program);
    void delete_queries(GLsizei n, GLuint const* ids);
    void delete_renderbuffers(GLsizei n, GLuint const* renderbuffers);
    void delete_samplers(GLsizei count, GLuint const* samplers);
    void delete_shader(GLuint shader);
    void delete_sync(GLsync sync);
    void delete_textures(GLsizei n, GLuint const* textures);
    void delete_transform_feedbacks(GLsizei n, GLuint const* ids);
    void delete_vertex_arrays(GLsizei n, GLuint const* arrays);
    void delete_vertex_arrays_oes(GLsizei n, GLuint const* arrays);
    void depth_func(GLenum func);
    void depth_mask(GLboolean flag);
    void depth_rangef(GLfloat n, GLfloat f);
    void detach_shader(GLuint program, GLuint shader);
    void disable(GLenum cap);
    void disable_vertex_attrib_array(GLuint index);
    void draw_arrays(GLenum mode, GLint first, GLsizei count);
    void draw_arrays_instanced(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
    void draw_arrays_instanced_angle(GLenum mode, GLint first, GLsizei count, GLsizei primcount);
    void draw_buffers(GLsizei n, GLenum const* bufs);
    void draw_buffers_ext(GLsizei n, GLenum const* bufs);
    void draw_elements(GLenum mode, GLsizei count, GLenum type, void const* indices);
    void draw_elements_instanced(GLenum mode, GLsizei count, GLenum type, void const* indices, GLsizei instancecount);
    void draw_elements_instanced_angle(GLenum mode, GLsizei count, GLenum type, void const* indices, GLsizei primcount);
    void draw_range_elements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void const* indices);
    void enable(GLenum cap);
    void enable_vertex_attrib_array(GLuint index);
    void end_query(GLenum target);
    void end_transform_feedback();
    GLsync fence_sync(GLenum condition, GLbitfield flags);
    void finish();
    void flush();
    void framebuffer_renderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
    void framebuffer_texture2d(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
    void framebuffer_texture_layer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
    void front_face(GLenum mode);
    void gen_buffers(GLsizei n, GLuint* buffers);
    void gen_framebuffers(GLsizei n, GLuint* framebuffers);
    void gen_queries(GLsizei n, GLuint* ids);
    void gen_renderbuffers(GLsizei n, GLuint* renderbuffers);
    void gen_samplers(GLsizei count, GLuint* samplers);
    void gen_textures(GLsizei n, GLuint* textures);
    void gen_transform_feedbacks(GLsizei n, GLuint* ids);
    void gen_vertex_arrays(GLsizei n, GLuint* arrays);
    void gen_vertex_arrays_oes(GLsizei n, GLuint* arrays);
    void generate_mipmap(GLenum target);
    void get_active_attrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
    void get_active_uniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
    void get_active_uniform_block_name(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName);
    void get_active_uniform_blockiv_robust_angle(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* params);
    void get_active_uniformsiv(GLuint program, GLsizei uniformCount, GLuint const* uniformIndices, GLenum pname, GLint* params);
    GLint get_attrib_location(GLuint program, GLchar const* name);
    void get_booleanv_robust_angle(GLenum pname, GLsizei bufSize, GLsizei* length, GLboolean* data);
    void get_buffer_parameteriv_robust_angle(GLenum target, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* params);
    GLenum get_error();
    void get_floatv_robust_angle(GLenum pname, GLsizei bufSize, GLsizei* length, GLfloat* data);
    void get_integer64v_robust_angle(GLenum pname, GLsizei bufSize, GLsizei* length, GLint64* data);
    void get_integerv_robust_angle(GLenum pname, GLsizei bufSize, GLsizei* length, GLint* data);
    void get_internalformativ_robust_angle(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* params);
    void get_program_info_log(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
    void get_programiv(GLuint program, GLenum pname, GLint* params);
    void get_programiv_robust_angle(GLuint program, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* params);
    void get_query_objectuiv_robust_angle(GLuint id, GLenum pname, GLsizei bufSize, GLsizei* length, GLuint* params);
    void get_renderbuffer_parameteriv_robust_angle(GLenum target, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* params);
    void get_shader_info_log(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
    void get_shader_precision_format(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
    void get_shader_source(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* source);
    void get_shaderiv(GLuint shader, GLenum pname, GLint* params);
    void get_shaderiv_robust_angle(GLuint shader, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* params);
    GLubyte const* get_string(GLenum name);
    void get_synciv(GLsync sync, GLenum pname, GLsizei count, GLsizei* length, GLint* values);
    void get_tex_parameterfv_robust_angle(GLenum target, GLenum pname, GLsizei bufSize, GLsizei* length, GLfloat* params);
    void get_tex_parameteriv_robust_angle(GLenum target, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* params);
    GLuint get_uniform_block_index(GLuint program, GLchar const* uniformBlockName);
    void get_uniform_indices(GLuint program, GLsizei uniformCount, GLchar const* const* uniformNames, GLuint* uniformIndices);
    GLint get_uniform_location(GLuint program, GLchar const* name);
    void get_vertex_attrib_pointerv_robust_angle(GLuint index, GLenum pname, GLsizei bufSize, GLsizei* length, void** pointer);
    void get_vertex_attribfv_robust_angle(GLuint index, GLenum pname, GLsizei bufSize, GLsizei* length, GLfloat* params);
    void get_vertex_attribiv_robust_angle(GLuint index, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* params);
    void hint(GLenum target, GLenum mode);
    void invalidate_framebuffer(GLenum target, GLsizei numAttachments, GLenum const* attachments);
    void invalidate_sub_framebuffer(GLenum target, GLsizei numAttachments, GLenum const* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
    GLboolean is_buffer(GLuint buffer);
    GLboolean is_enabled(GLenum cap);
    GLboolean is_framebuffer(GLuint framebuffer);
    GLboolean is_program(GLuint program);
    GLboolean is_renderbuffer(GLuint renderbuffer);
    GLboolean is_shader(GLuint shader);
    GLboolean is_texture(GLuint texture);
    GLboolean is_vertex_array(GLuint array);
    GLboolean is_vertex_array_oes(GLuint array);
    void line_width(GLfloat width);
    void link_program(GLuint program);
    void* map_buffer_range(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
    void pause_transform_feedback();
    void pixel_storei(GLenum pname, GLint param);
    void polygon_offset(GLfloat factor, GLfloat units);
    void read_buffer(GLenum src);
    void read_pixels_robust_angle(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLsizei* length, GLsizei* columns, GLsizei* rows, void* pixels);
    void renderbuffer_storage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
    void renderbuffer_storage_multisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
    void request_extension_angle(GLchar const* name);
    void resume_transform_feedback();
    void sample_coverage(GLfloat value, GLboolean invert);
    void sampler_parameterf(GLuint sampler, GLenum pname, GLfloat param);
    void sampler_parameteri(GLuint sampler, GLenum pname, GLint param);
    void scissor(GLint x, GLint y, GLsizei width, GLsizei height);
    void shader_source(GLuint shader, GLsizei count, GLchar const* const* string, GLint const* length);
    void stencil_func(GLenum func, GLint ref, GLuint mask);
    void stencil_func_separate(GLenum face, GLenum func, GLint ref, GLuint mask);
    void stencil_mask(GLuint mask);
    void stencil_mask_separate(GLenum face, GLuint mask);
    void stencil_op(GLenum fail, GLenum zfail, GLenum zpass);
    void stencil_op_separate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
    void tex_image2d_robust_angle(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLsizei bufSize, void const* pixels);
    void tex_image3d_robust_angle(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLsizei bufSize, void const* pixels);
    void tex_parameterf(GLenum target, GLenum pname, GLfloat param);
    void tex_parameteri(GLenum target, GLenum pname, GLint param);
    void tex_storage2d(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
    void tex_storage3d(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
    void tex_sub_image2d_robust_angle(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void const* pixels);
    void tex_sub_image3d_robust_angle(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void const* pixels);
    void transform_feedback_varyings(GLuint program, GLsizei count, GLchar const* const* varyings, GLenum bufferMode);
    void uniform1f(GLint location, GLfloat v0);
    void uniform1fv(GLint location, GLsizei count, GLfloat const* value);
    void uniform1i(GLint location, GLint v0);
    void uniform1iv(GLint location, GLsizei count, GLint const* value);
    void uniform1ui(GLint location, GLuint v0);
    void uniform1uiv(GLint location, GLsizei count, GLuint const* value);
    void uniform2f(GLint location, GLfloat v0, GLfloat v1);
    void uniform2fv(GLint location, GLsizei count, GLfloat const* value);
    void uniform2i(GLint location, GLint v0, GLint v1);
    void uniform2iv(GLint location, GLsizei count, GLint const* value);
    void uniform2ui(GLint location, GLuint v0, GLuint v1);
    void uniform2uiv(GLint location, GLsizei count, GLuint const* value);
    void uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
    void uniform3fv(GLint location, GLsizei count, GLfloat const* value);
    void uniform3i(GLint location, GLint v0, GLint v1, GLint v2);
    void uniform3iv(GLint location, GLsizei count, GLint const* value);
    void uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2);
    void uniform3uiv(GLint location, GLsizei count, GLuint const* value);
    void uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
    void uniform4fv(GLint location, GLsizei count, GLfloat const* value);
    void uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
    void uniform4iv(GLint location, GLsizei count, GLint const* value);
    void uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
    void uniform4uiv(GLint location, GLsizei count, GLuint const* value);
    void uniform_block_binding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
    void uniform_matrix2fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    void uniform_matrix2x3fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    void uniform_matrix2x4fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    void uniform_matrix3fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    void uniform_matrix3x2fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    void uniform_matrix3x4fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    void uniform_matrix4fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    void uniform_matrix4x2fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    void uniform_matrix4x3fv(GLint location, GLsizei count, GLboolean transpose, GLfloat const* value);
    GLboolean unmap_buffer(GLenum target);
    void use_program(GLuint program);
    void validate_program(GLuint program);
    void vertex_attrib1f(GLuint index, GLfloat x);
    void vertex_attrib1fv(GLuint index, GLfloat const* v);
    void vertex_attrib2f(GLuint index, GLfloat x, GLfloat y);
    void vertex_attrib2fv(GLuint index, GLfloat const* v);
    void vertex_attrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
    void vertex_attrib3fv(GLuint index, GLfloat const* v);
    void vertex_attrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
    void vertex_attrib4fv(GLuint index, GLfloat const* v);
    void vertex_attrib_divisor(GLuint index, GLuint divisor);
    void vertex_attrib_divisor_angle(GLuint index, GLuint divisor);
    void vertex_attrib_i4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
    void vertex_attrib_i4iv(GLuint index, GLint const* v);
    void vertex_attrib_i4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
    void vertex_attrib_i4uiv(GLuint index, GLuint const* v);
    void vertex_attrib_i_pointer(GLuint index, GLint size, GLenum type, GLsizei stride, void const* pointer);
    void vertex_attrib_pointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, void const* pointer);
    void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
    void wait_sync(GLsync sync, GLbitfield flags, GLuint64 timeout);
};

}
