#pragma once

#include "renderer_api/renderer_api.h"

#include <array>
#include <cstdint>
#include <span>
#include <string>
#include <string_view>
#include <vector>

namespace pp::renderer::gl {

struct OpenGlAttributeBinding;

struct OpenGlRuntime {
    bool desktop_gl = false;
    bool gles = false;
    bool web = false;
};

struct OpenGlCapabilities {
    bool framebuffer_fetch = false;
    bool map_buffer_alignment = false;
    bool float32_textures = false;
    bool float32_linear = false;
    bool float16_textures = false;
};

struct OpenGlFeatureState {
    OpenGlCapabilities capabilities;
    pp::renderer::RenderDeviceFeatures features;
};

struct OpenGlCapabilityDetectionResult {
    std::vector<std::string> extensions;
    OpenGlFeatureState feature_state;
};

struct OpenGlPixelFormat {
    std::uint32_t internal_format = 0;
    std::uint32_t pixel_format = 0;
    std::uint32_t channel_count = 0;
};

struct OpenGlTextureParameter {
    std::uint32_t name = 0;
    std::uint32_t value = 0;
};

struct OpenGlSamplerState {
    std::uint32_t min_filter = 0;
    std::uint32_t mag_filter = 0;
    std::uint32_t wrap_s = 0;
    std::uint32_t wrap_t = 0;
    std::uint32_t wrap_r = 0;
    bool supported = false;
};

struct OpenGlViewportRect {
    std::int32_t x = 0;
    std::int32_t y = 0;
    std::int32_t width = 0;
    std::int32_t height = 0;
    float min_depth = 0.0F;
    float max_depth = 1.0F;
};

struct OpenGlScissorRect {
    std::uint8_t enabled = 0;
    std::int32_t x = 0;
    std::int32_t y = 0;
    std::int32_t width = 0;
    std::int32_t height = 0;
};

struct OpenGlEnumMapping {
    std::uint32_t value = 0;
    bool supported = false;
};

struct OpenGlColorWriteMask {
    std::uint8_t r = 0;
    std::uint8_t g = 0;
    std::uint8_t b = 0;
    std::uint8_t a = 0;
};

struct OpenGlClearValues {
    std::array<float, 4> color {};
    float depth = 1.0F;
    std::uint8_t stencil = 0;
};

struct OpenGlBlendState {
    std::uint8_t enabled = 0;
    std::uint32_t source_color_factor = 0;
    std::uint32_t destination_color_factor = 0;
    std::uint32_t color_equation = 0;
    std::uint32_t source_alpha_factor = 0;
    std::uint32_t destination_alpha_factor = 0;
    std::uint32_t alpha_equation = 0;
    OpenGlColorWriteMask color_write_mask;
    bool supported = false;
};

struct OpenGlDepthState {
    std::uint8_t test_enabled = 0;
    std::uint8_t write_enabled = 0;
    std::uint32_t compare_function = 0;
    bool supported = false;
};

struct OpenGlReadbackFormat {
    std::uint32_t pixel_format = 0;
    std::uint32_t component_type = 0;
    std::uint32_t bytes_per_pixel = 0;
};

struct OpenGlRendererTextureFormat {
    std::uint32_t internal_format = 0;
    std::uint32_t pixel_format = 0;
    std::uint32_t component_type = 0;
    std::uint32_t bytes_per_pixel = 0;
};

struct OpenGlTexture2DAllocation {
    std::int32_t width = 0;
    std::int32_t height = 0;
    std::int32_t internal_format = 0;
    std::uint32_t pixel_format = 0;
    std::uint32_t component_type = 0;
    const void* data = nullptr;
};

struct OpenGlTextureCubeAllocation {
    std::int32_t resolution = 0;
    std::int32_t internal_format = 0;
    std::uint32_t pixel_format = 0;
    std::uint32_t component_type = 0;
};

struct OpenGlTexture2DUpdate {
    std::uint32_t texture_id = 0;
    std::int32_t x = 0;
    std::int32_t y = 0;
    std::int32_t width = 0;
    std::int32_t height = 0;
    std::uint32_t pixel_format = 0;
    std::uint32_t component_type = 0;
    const void* data = nullptr;
};

struct OpenGlTexture2DFramebufferCopy {
    std::uint32_t texture_target = 0;
    std::int32_t level = 0;
    std::int32_t destination_x = 0;
    std::int32_t destination_y = 0;
    std::int32_t source_x = 0;
    std::int32_t source_y = 0;
    std::int32_t width = 0;
    std::int32_t height = 0;
};

struct OpenGlTexture2DReadback {
    std::uint32_t texture_id = 0;
    std::int32_t width = 0;
    std::int32_t height = 0;
    OpenGlReadbackFormat format;
    void* pixels = nullptr;
};

struct OpenGlTexture2DReadbackResult {
    std::uint32_t framebuffer_status = 0;
    bool pixels_read = false;
};

struct OpenGlRenderTargetFramebufferAllocationResult {
    std::uint32_t framebuffer_id = 0;
    std::uint32_t framebuffer_status = 0;
};

struct OpenGlShaderCompileInfo {
    std::uint32_t shader_id = 0;
    std::int32_t compile_status = 0;
    std::int32_t info_log_length = 0;
};

struct OpenGlProgramLinkInfo {
    std::uint32_t program_id = 0;
    std::int32_t link_status = 0;
    std::int32_t info_log_length = 0;
};

struct OpenGlActiveUniformInfo {
    std::int32_t length = 0;
    std::int32_t size = 0;
    std::uint32_t type = 0;
};

struct OpenGlVertexAttribute {
    std::uint32_t index = 0;
    std::int32_t component_count = 0;
    std::uint32_t component_type = 0;
    std::uint8_t normalized = 0;
    std::int32_t stride = 0;
    std::uintptr_t offset = 0;
};

struct OpenGlMeshUpload {
    const void* vertex_data = nullptr;
    std::intptr_t vertex_byte_count = 0;
    const void* index_data = nullptr;
    std::intptr_t index_byte_count = 0;
    bool indexed = false;
    std::uint32_t vertex_array_count = 2;
    std::span<const OpenGlVertexAttribute> attributes;
};

struct OpenGlMeshObjects {
    std::uint32_t vertex_buffer = 0;
    std::uint32_t index_buffer = 0;
    std::array<std::uint32_t, 2> vertex_arrays {};
};

struct OpenGlBufferUpload {
    std::uint32_t target = 0;
    std::uint32_t buffer_id = 0;
    const void* data = nullptr;
    std::intptr_t byte_count = 0;
    std::uint32_t usage = 0;
};

struct OpenGlMeshDraw {
    std::uint32_t vertex_array = 0;
    std::uint32_t mode = 0;
    std::int32_t count = 0;
    bool indexed = false;
    std::uint32_t index_type = 0;
    const void* index_offset = nullptr;
};

struct OpenGlMeshDelete {
    std::array<std::uint32_t, 2> buffers {};
    std::array<std::uint32_t, 2> vertex_arrays {};
};

struct OpenGlFramebufferRect {
    std::int32_t x0 = 0;
    std::int32_t y0 = 0;
    std::int32_t x1 = 0;
    std::int32_t y1 = 0;
};

struct OpenGlFramebufferBlit {
    std::uint32_t source_framebuffer = 0;
    std::uint32_t destination_framebuffer = 0;
    OpenGlFramebufferRect source_rect;
    OpenGlFramebufferRect destination_rect;
    std::uint32_t mask = 0;
    std::uint32_t filter = 0;
};

struct OpenGlFramebufferReadback {
    std::uint32_t framebuffer = 0;
    std::int32_t x = 0;
    std::int32_t y = 0;
    std::int32_t width = 0;
    std::int32_t height = 0;
    OpenGlReadbackFormat format;
    void* pixels = nullptr;
};

struct OpenGlFramebufferBindingState {
    std::int32_t draw_framebuffer = 0;
    std::int32_t read_framebuffer = 0;
};

struct OpenGlWindowsWglContextConfig {
    std::array<std::int32_t, 9> context_attributes {};
    std::array<std::int32_t, 15> pixel_format_attributes {};
};

struct OpenGlInitialState {
    bool depth_test_enabled = false;
    std::uint32_t depth_test_state = 0;
    std::uint32_t source_color_factor = 0;
    std::uint32_t destination_color_factor = 0;
    std::uint32_t color_equation = 0;
    std::uint32_t alpha_equation = 0;
};

struct OpenGlConvertCommandState {
    bool depth_test_enabled = false;
    bool program_point_size_enabled = false;
    std::uint32_t depth_test_state = 0;
    std::uint32_t program_point_size_state = 0;
    std::uint32_t source_color_factor = 0;
    std::uint32_t destination_color_factor = 0;
    std::uint32_t blend_equation = 0;
};

struct OpenGlSavedState {
    std::uint8_t blend_enabled = 0;
    std::uint8_t depth_test_enabled = 0;
    std::uint8_t scissor_test_enabled = 0;
    std::array<std::int32_t, 4> viewport {};
    std::array<float, 4> clear_color {};
    std::array<std::int32_t, 10> texture_2d_bindings {};
    std::array<std::int32_t, 10> sampler_bindings {};
    std::int32_t cube_map_binding = 0;
    std::int32_t program = 0;
    std::int32_t draw_framebuffer = 0;
    std::int32_t read_framebuffer = 0;
    std::int32_t active_texture = 0;
};

using OpenGlCapabilityFn = void (*)(std::uint32_t state) noexcept;
using OpenGlIsEnabledFn = std::uint8_t (*)(std::uint32_t state) noexcept;
using OpenGlGetIntegerFn = void (*)(std::uint32_t name, std::int32_t* value) noexcept;
using OpenGlGetFloatFn = void (*)(std::uint32_t name, float* value) noexcept;
using OpenGlGetBooleanFn = void (*)(std::uint32_t name, std::uint8_t* value) noexcept;
using OpenGlActiveTextureFn = void (*)(std::uint32_t texture_unit) noexcept;
using OpenGlClearColorFn = void (*)(float r, float g, float b, float a) noexcept;
using OpenGlClearFn = void (*)(std::uint32_t mask) noexcept;
using OpenGlColorMaskFn = void (*)(
    std::uint8_t r,
    std::uint8_t g,
    std::uint8_t b,
    std::uint8_t a) noexcept;
using OpenGlViewportFn = void (*)(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept;
using OpenGlScissorFn = void (*)(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height) noexcept;
using OpenGlBlendFuncFn = void (*)(std::uint32_t source_factor, std::uint32_t destination_factor) noexcept;
using OpenGlBlendEquationFn = void (*)(std::uint32_t equation) noexcept;
using OpenGlBlendEquationSeparateFn = void (*)(std::uint32_t color_equation, std::uint32_t alpha_equation) noexcept;
using OpenGlUseProgramFn = void (*)(std::uint32_t program) noexcept;
using OpenGlDeleteProgramFn = void (*)(std::uint32_t program) noexcept;
using OpenGlUniform4fvFn = void (*)(std::int32_t location, std::int32_t count, const float* values) noexcept;
using OpenGlUniform3fvFn = void (*)(std::int32_t location, std::int32_t count, const float* values) noexcept;
using OpenGlUniform2fvFn = void (*)(std::int32_t location, std::int32_t count, const float* values) noexcept;
using OpenGlUniformMatrix4fvFn = void (*)(
    std::int32_t location,
    std::int32_t count,
    std::uint8_t transpose,
    const float* values) noexcept;
using OpenGlUniform1iFn = void (*)(std::int32_t location, std::int32_t value) noexcept;
using OpenGlUniform1fFn = void (*)(std::int32_t location, float value) noexcept;
using OpenGlGetAttribLocationFn = std::int32_t (*)(std::uint32_t program, const char* name) noexcept;
using OpenGlCreateShaderFn = std::uint32_t (*)(std::uint32_t stage) noexcept;
using OpenGlShaderSourceFn = void (*)(
    std::uint32_t shader,
    std::int32_t count,
    const char* const* sources) noexcept;
using OpenGlCompileShaderFn = void (*)(std::uint32_t shader) noexcept;
using OpenGlGetShaderIntegerFn = void (*)(
    std::uint32_t shader,
    std::uint32_t query,
    std::int32_t* value) noexcept;
using OpenGlGetShaderInfoLogFn = void (*)(
    std::uint32_t shader,
    std::int32_t capacity,
    std::int32_t* length,
    char* info_log) noexcept;
using OpenGlDeleteShaderFn = void (*)(std::uint32_t shader) noexcept;
using OpenGlCreateProgramFn = std::uint32_t (*)() noexcept;
using OpenGlAttachShaderFn = void (*)(std::uint32_t program, std::uint32_t shader) noexcept;
using OpenGlLinkProgramFn = void (*)(std::uint32_t program) noexcept;
using OpenGlBindAttribLocationFn = void (*)(
    std::uint32_t program,
    std::uint32_t location,
    const char* name) noexcept;
using OpenGlGetProgramIntegerFn = void (*)(
    std::uint32_t program,
    std::uint32_t query,
    std::int32_t* value) noexcept;
using OpenGlGetProgramInfoLogFn = void (*)(
    std::uint32_t program,
    std::int32_t capacity,
    std::int32_t* length,
    char* info_log) noexcept;
using OpenGlGetActiveUniformFn = void (*)(
    std::uint32_t program,
    std::uint32_t index,
    std::int32_t capacity,
    std::int32_t* length,
    std::int32_t* size,
    std::uint32_t* type,
    char* name) noexcept;
using OpenGlGetUniformLocationFn = std::int32_t (*)(std::uint32_t program, const char* name) noexcept;
using OpenGlBindFramebufferFn = void (*)(std::uint32_t target, std::uint32_t framebuffer) noexcept;
using OpenGlBindRenderbufferFn = void (*)(std::uint32_t target, std::uint32_t renderbuffer) noexcept;
using OpenGlBindTextureFn = void (*)(std::uint32_t target, std::uint32_t texture) noexcept;
using OpenGlBindSamplerFn = void (*)(std::uint32_t unit, std::uint32_t sampler) noexcept;
using OpenGlRenderbufferStorageFn = void (*)(
    std::uint32_t target,
    std::uint32_t internal_format,
    std::int32_t width,
    std::int32_t height) noexcept;
using OpenGlSamplerParameteriFn = void (*)(
    std::uint32_t sampler,
    std::uint32_t parameter,
    std::int32_t value) noexcept;
using OpenGlSamplerParameterfvFn = void (*)(
    std::uint32_t sampler,
    std::uint32_t parameter,
    const float* values) noexcept;
using OpenGlGenObjectsFn = void (*)(std::uint32_t count, std::uint32_t* ids) noexcept;
using OpenGlDeleteObjectsFn = void (*)(std::uint32_t count, const std::uint32_t* ids) noexcept;
using OpenGlBindBufferFn = void (*)(std::uint32_t target, std::uint32_t buffer) noexcept;
using OpenGlBufferDataFn = void (*)(
    std::uint32_t target,
    std::intptr_t byte_count,
    const void* data,
    std::uint32_t usage) noexcept;
using OpenGlMapBufferRangeFn = void* (*)(
    std::uint32_t target,
    std::intptr_t offset,
    std::intptr_t byte_count,
    std::uint32_t access) noexcept;
using OpenGlUnmapBufferFn = void (*)(std::uint32_t target) noexcept;
using OpenGlBindVertexArrayFn = void (*)(std::uint32_t vertex_array) noexcept;
using OpenGlEnableVertexAttribArrayFn = void (*)(std::uint32_t index) noexcept;
using OpenGlVertexAttribPointerFn = void (*)(
    std::uint32_t index,
    std::int32_t component_count,
    std::uint32_t component_type,
    std::uint8_t normalized,
    std::int32_t stride,
    const void* offset) noexcept;
using OpenGlDrawElementsFn = void (*)(
    std::uint32_t mode,
    std::int32_t count,
    std::uint32_t index_type,
    const void* index_offset) noexcept;
using OpenGlDrawArraysFn = void (*)(
    std::uint32_t mode,
    std::int32_t first,
    std::int32_t count) noexcept;
using OpenGlTexImage2DFn = void (*)(
    std::uint32_t target,
    std::int32_t level,
    std::int32_t internal_format,
    std::int32_t width,
    std::int32_t height,
    std::int32_t border,
    std::uint32_t pixel_format,
    std::uint32_t component_type,
    const void* data) noexcept;
using OpenGlTexSubImage2DFn = void (*)(
    std::uint32_t target,
    std::int32_t level,
    std::int32_t x,
    std::int32_t y,
    std::int32_t width,
    std::int32_t height,
    std::uint32_t pixel_format,
    std::uint32_t component_type,
    const void* data) noexcept;
using OpenGlTexParameterfFn = void (*)(std::uint32_t target, std::uint32_t parameter, float value) noexcept;
using OpenGlCopyTexSubImage2DFn = void (*)(
    std::uint32_t target,
    std::int32_t level,
    std::int32_t destination_x,
    std::int32_t destination_y,
    std::int32_t source_x,
    std::int32_t source_y,
    std::int32_t width,
    std::int32_t height) noexcept;
using OpenGlGenerateMipmapFn = void (*)(std::uint32_t target) noexcept;
using OpenGlFramebufferTexture2DFn = void (*)(
    std::uint32_t target,
    std::uint32_t attachment,
    std::uint32_t texture_target,
    std::uint32_t texture,
    std::int32_t level) noexcept;
using OpenGlFramebufferRenderbufferFn = void (*)(
    std::uint32_t target,
    std::uint32_t attachment,
    std::uint32_t renderbuffer_target,
    std::uint32_t renderbuffer) noexcept;
using OpenGlCheckFramebufferStatusFn = std::uint32_t (*)(std::uint32_t target) noexcept;
using OpenGlReadPixelsFn = void (*)(
    std::int32_t x,
    std::int32_t y,
    std::int32_t width,
    std::int32_t height,
    std::uint32_t pixel_format,
    std::uint32_t component_type,
    void* pixels) noexcept;
using OpenGlBlitFramebufferFn = void (*)(
    std::int32_t source_x0,
    std::int32_t source_y0,
    std::int32_t source_x1,
    std::int32_t source_y1,
    std::int32_t destination_x0,
    std::int32_t destination_y0,
    std::int32_t destination_x1,
    std::int32_t destination_y1,
    std::uint32_t mask,
    std::uint32_t filter) noexcept;

struct OpenGlStateDispatch {
    OpenGlCapabilityFn enable = nullptr;
    OpenGlCapabilityFn disable = nullptr;
    OpenGlBlendFuncFn blend_func = nullptr;
    OpenGlBlendEquationSeparateFn blend_equation_separate = nullptr;
};

struct OpenGlConvertCommandStateDispatch {
    OpenGlCapabilityFn enable = nullptr;
    OpenGlCapabilityFn disable = nullptr;
    OpenGlBlendFuncFn blend_func = nullptr;
    OpenGlBlendEquationFn blend_equation = nullptr;
};

struct OpenGlStateSnapshotDispatch {
    OpenGlIsEnabledFn is_enabled = nullptr;
    OpenGlGetIntegerFn get_integer = nullptr;
    OpenGlGetFloatFn get_float = nullptr;
    OpenGlActiveTextureFn active_texture = nullptr;
};

struct OpenGlStateRestoreDispatch {
    OpenGlCapabilityFn enable = nullptr;
    OpenGlCapabilityFn disable = nullptr;
    OpenGlViewportFn viewport = nullptr;
    OpenGlClearColorFn clear_color = nullptr;
    OpenGlBindFramebufferFn bind_framebuffer = nullptr;
    OpenGlUseProgramFn use_program = nullptr;
    OpenGlActiveTextureFn active_texture = nullptr;
    OpenGlBindTextureFn bind_texture = nullptr;
    OpenGlBindSamplerFn bind_sampler = nullptr;
};

struct OpenGlRuntimeInfo {
    const char* version = "";
    const char* vendor = "";
    const char* renderer = "";
    const char* shading_language_version = "";
};

using OpenGlStringQueryFn = const char* (*)(std::uint32_t name) noexcept;
using OpenGlIndexedStringQueryFn = const char* (*)(std::uint32_t name, std::uint32_t index) noexcept;

struct OpenGlRuntimeInfoDispatch {
    OpenGlStringQueryFn get_string = nullptr;
};

struct OpenGlExtensionQueryDispatch {
    OpenGlGetIntegerFn get_integer = nullptr;
    OpenGlIndexedStringQueryFn get_string_indexed = nullptr;
};

struct OpenGlDefaultClear {
    std::array<float, 4> color {};
    std::uint32_t mask = 0;
};

struct OpenGlColorMaskedClear {
    OpenGlColorWriteMask mask;
    std::array<float, 4> color {};
};

struct OpenGlClearDispatch {
    OpenGlClearColorFn clear_color = nullptr;
    OpenGlClearFn clear = nullptr;
};

struct OpenGlClearColorDispatch {
    OpenGlClearColorFn clear_color = nullptr;
};

struct OpenGlActiveTextureDispatch {
    OpenGlActiveTextureFn active_texture = nullptr;
};

struct OpenGlViewportQueryDispatch {
    OpenGlGetIntegerFn get_integer = nullptr;
};

struct OpenGlClearColorQueryDispatch {
    OpenGlGetFloatFn get_float = nullptr;
};

struct OpenGlColorMaskedClearDispatch {
    OpenGlGetBooleanFn get_boolean = nullptr;
    OpenGlColorMaskFn color_mask = nullptr;
    OpenGlClearColorFn clear_color = nullptr;
    OpenGlClearFn clear = nullptr;
};

struct OpenGlColorWriteMaskDispatch {
    OpenGlColorMaskFn color_mask = nullptr;
};

struct OpenGlViewportDispatch {
    OpenGlViewportFn viewport = nullptr;
};

struct OpenGlScissorDispatch {
    OpenGlCapabilityFn enable = nullptr;
    OpenGlCapabilityFn disable = nullptr;
    OpenGlScissorFn scissor = nullptr;
};

struct OpenGlScissorTestDispatch {
    OpenGlCapabilityFn enable = nullptr;
    OpenGlCapabilityFn disable = nullptr;
};

struct OpenGlCapabilityDispatch {
    OpenGlCapabilityFn enable = nullptr;
    OpenGlCapabilityFn disable = nullptr;
};

struct OpenGlCapabilityStateQueryDispatch {
    OpenGlIsEnabledFn is_enabled = nullptr;
};

struct OpenGlRenderPlatformHintDispatch {
    OpenGlCapabilityFn enable = nullptr;
};

struct OpenGlDebugOutputStateDispatch {
    OpenGlCapabilityFn enable = nullptr;
};

struct OpenGlBufferClearDispatch {
    OpenGlClearFn clear = nullptr;
};

struct OpenGlTexture2DAllocationDispatch {
    OpenGlGenObjectsFn gen_textures = nullptr;
    OpenGlBindTextureFn bind_texture = nullptr;
    OpenGlTexImage2DFn tex_image_2d = nullptr;
};

struct OpenGlTexture2DDeleteDispatch {
    OpenGlDeleteObjectsFn delete_textures = nullptr;
};

struct OpenGlTextureCubeAllocationDispatch {
    OpenGlGenObjectsFn gen_textures = nullptr;
    OpenGlBindTextureFn bind_texture = nullptr;
    OpenGlTexImage2DFn tex_image_2d = nullptr;
};

struct OpenGlTexture2DBindDispatch {
    OpenGlBindTextureFn bind_texture = nullptr;
};

struct OpenGlTexture2DUpdateDispatch {
    OpenGlBindTextureFn bind_texture = nullptr;
    OpenGlTexSubImage2DFn tex_sub_image_2d = nullptr;
};

struct OpenGlTexture2DParameterDispatch {
    OpenGlBindTextureFn bind_texture = nullptr;
    OpenGlTexParameterfFn tex_parameter_f = nullptr;
};

struct OpenGlTexture2DFramebufferCopyDispatch {
    OpenGlCopyTexSubImage2DFn copy_tex_sub_image_2d = nullptr;
};

struct OpenGlTexture2DMipmapDispatch {
    OpenGlBindTextureFn bind_texture = nullptr;
    OpenGlGenerateMipmapFn generate_mipmap = nullptr;
};

struct OpenGlTexture2DReadbackDispatch {
    OpenGlBindTextureFn bind_texture = nullptr;
    OpenGlGenObjectsFn gen_framebuffers = nullptr;
    OpenGlGetIntegerFn get_integer = nullptr;
    OpenGlBindFramebufferFn bind_framebuffer = nullptr;
    OpenGlFramebufferTexture2DFn framebuffer_texture_2d = nullptr;
    OpenGlCheckFramebufferStatusFn check_framebuffer_status = nullptr;
    OpenGlReadPixelsFn read_pixels = nullptr;
    OpenGlDeleteObjectsFn delete_framebuffers = nullptr;
};

struct OpenGlFramebufferBlitDispatch {
    OpenGlGetIntegerFn get_integer = nullptr;
    OpenGlBindFramebufferFn bind_framebuffer = nullptr;
    OpenGlBlitFramebufferFn blit_framebuffer = nullptr;
};

struct OpenGlFramebufferReadbackDispatch {
    OpenGlGetIntegerFn get_integer = nullptr;
    OpenGlBindFramebufferFn bind_framebuffer = nullptr;
    OpenGlReadPixelsFn read_pixels = nullptr;
};

struct OpenGlFramebufferBindDispatch {
    OpenGlGetIntegerFn get_integer = nullptr;
    OpenGlBindFramebufferFn bind_framebuffer = nullptr;
};

struct OpenGlFramebufferRestoreDispatch {
    OpenGlBindFramebufferFn bind_framebuffer = nullptr;
};

struct OpenGlRenderTargetFramebufferAllocationDispatch {
    OpenGlGenObjectsFn gen_framebuffers = nullptr;
    OpenGlGetIntegerFn get_integer = nullptr;
    OpenGlBindFramebufferFn bind_framebuffer = nullptr;
    OpenGlFramebufferTexture2DFn framebuffer_texture_2d = nullptr;
    OpenGlFramebufferRenderbufferFn framebuffer_renderbuffer = nullptr;
    OpenGlCheckFramebufferStatusFn check_framebuffer_status = nullptr;
};

struct OpenGlFramebufferDeleteDispatch {
    OpenGlDeleteObjectsFn delete_framebuffers = nullptr;
};

struct OpenGlPixelBufferAllocationDispatch {
    OpenGlGenObjectsFn gen_buffers = nullptr;
};

struct OpenGlPixelBufferReadbackDispatch {
    OpenGlGenObjectsFn gen_buffers = nullptr;
    OpenGlBindBufferFn bind_buffer = nullptr;
    OpenGlBufferDataFn buffer_data = nullptr;
    OpenGlReadPixelsFn read_pixels = nullptr;
};

struct OpenGlPixelBufferMapDispatch {
    OpenGlBindBufferFn bind_buffer = nullptr;
    OpenGlMapBufferRangeFn map_buffer_range = nullptr;
};

struct OpenGlPixelBufferUnmapDispatch {
    OpenGlBindBufferFn bind_buffer = nullptr;
    OpenGlUnmapBufferFn unmap_buffer = nullptr;
};

struct OpenGlPixelBufferDeleteDispatch {
    OpenGlDeleteObjectsFn delete_buffers = nullptr;
};

struct OpenGlDepthRenderbufferAllocationDispatch {
    OpenGlGenObjectsFn gen_renderbuffers = nullptr;
    OpenGlBindRenderbufferFn bind_renderbuffer = nullptr;
    OpenGlRenderbufferStorageFn renderbuffer_storage = nullptr;
};

struct OpenGlRenderbufferDeleteDispatch {
    OpenGlDeleteObjectsFn delete_renderbuffers = nullptr;
};

struct OpenGlDepthRenderbufferAttachmentDispatch {
    OpenGlFramebufferRenderbufferFn framebuffer_renderbuffer = nullptr;
};

struct OpenGlSamplerCreateDispatch {
    OpenGlGenObjectsFn gen_samplers = nullptr;
    OpenGlSamplerParameteriFn sampler_parameter_i = nullptr;
};

struct OpenGlSamplerParameterDispatch {
    OpenGlSamplerParameteriFn sampler_parameter_i = nullptr;
};

struct OpenGlSamplerBorderDispatch {
    OpenGlSamplerParameterfvFn sampler_parameter_fv = nullptr;
};

struct OpenGlSamplerBindDispatch {
    OpenGlBindSamplerFn bind_sampler = nullptr;
};

struct OpenGlProgramUseDispatch {
    OpenGlUseProgramFn use_program = nullptr;
};

struct OpenGlProgramDeleteDispatch {
    OpenGlUseProgramFn use_program = nullptr;
    OpenGlDeleteProgramFn delete_program = nullptr;
};

struct OpenGlUniformVec4Dispatch {
    OpenGlUniform4fvFn uniform_4fv = nullptr;
};

struct OpenGlUniformVec3Dispatch {
    OpenGlUniform3fvFn uniform_3fv = nullptr;
};

struct OpenGlUniformVec2Dispatch {
    OpenGlUniform2fvFn uniform_2fv = nullptr;
};

struct OpenGlUniformMat4Dispatch {
    OpenGlUniformMatrix4fvFn uniform_matrix_4fv = nullptr;
};

struct OpenGlUniformIntDispatch {
    OpenGlUniform1iFn uniform_1i = nullptr;
};

struct OpenGlUniformFloatDispatch {
    OpenGlUniform1fFn uniform_1f = nullptr;
};

struct OpenGlAttributeLocationDispatch {
    OpenGlGetAttribLocationFn get_attrib_location = nullptr;
};

struct OpenGlShaderCompileDispatch {
    OpenGlCreateShaderFn create_shader = nullptr;
    OpenGlShaderSourceFn shader_source = nullptr;
    OpenGlCompileShaderFn compile_shader = nullptr;
    OpenGlGetShaderIntegerFn get_shader_integer = nullptr;
    OpenGlGetShaderInfoLogFn get_shader_info_log = nullptr;
};

struct OpenGlShaderDeleteDispatch {
    OpenGlDeleteShaderFn delete_shader = nullptr;
};

struct OpenGlProgramLinkDispatch {
    OpenGlCreateProgramFn create_program = nullptr;
    OpenGlAttachShaderFn attach_shader = nullptr;
    OpenGlDeleteShaderFn delete_shader = nullptr;
    OpenGlLinkProgramFn link_program = nullptr;
    OpenGlGetAttribLocationFn get_attrib_location = nullptr;
    OpenGlBindAttribLocationFn bind_attrib_location = nullptr;
    OpenGlGetProgramIntegerFn get_program_integer = nullptr;
    OpenGlGetProgramInfoLogFn get_program_info_log = nullptr;
};

struct OpenGlProgramIntegerDispatch {
    OpenGlGetProgramIntegerFn get_program_integer = nullptr;
};

struct OpenGlActiveUniformDispatch {
    OpenGlGetActiveUniformFn get_active_uniform = nullptr;
};

struct OpenGlUniformLocationDispatch {
    OpenGlGetUniformLocationFn get_uniform_location = nullptr;
};

struct OpenGlMeshCreateDispatch {
    OpenGlGenObjectsFn gen_buffers = nullptr;
    OpenGlBindBufferFn bind_buffer = nullptr;
    OpenGlBufferDataFn buffer_data = nullptr;
    OpenGlGenObjectsFn gen_vertex_arrays = nullptr;
    OpenGlBindVertexArrayFn bind_vertex_array = nullptr;
    OpenGlEnableVertexAttribArrayFn enable_vertex_attrib_array = nullptr;
    OpenGlVertexAttribPointerFn vertex_attrib_pointer = nullptr;
};

struct OpenGlBufferUploadDispatch {
    OpenGlBindBufferFn bind_buffer = nullptr;
    OpenGlBufferDataFn buffer_data = nullptr;
};

struct OpenGlMeshDrawDispatch {
    OpenGlBindVertexArrayFn bind_vertex_array = nullptr;
    OpenGlDrawElementsFn draw_elements = nullptr;
    OpenGlDrawArraysFn draw_arrays = nullptr;
};

struct OpenGlMeshDeleteDispatch {
    OpenGlDeleteObjectsFn delete_buffers = nullptr;
    OpenGlDeleteObjectsFn delete_vertex_arrays = nullptr;
};

[[nodiscard]] OpenGlCapabilities detect_opengl_capabilities(
    std::span<const std::string_view> extensions,
    OpenGlRuntime runtime) noexcept;
[[nodiscard]] OpenGlRuntime opengl_runtime_for_current_build() noexcept;
[[nodiscard]] pp::renderer::RenderDeviceFeatures render_device_features(
    OpenGlCapabilities capabilities) noexcept;
[[nodiscard]] OpenGlFeatureState detect_opengl_feature_state(
    std::span<const std::string_view> extensions,
    OpenGlRuntime runtime) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlCapabilityDetectionResult> query_opengl_capability_detection(
    OpenGlExtensionQueryDispatch dispatch,
    OpenGlRuntime runtime);
[[nodiscard]] OpenGlInitialState panopainter_initial_state() noexcept;
[[nodiscard]] pp::foundation::Status apply_panopainter_initial_state(OpenGlStateDispatch dispatch) noexcept;
[[nodiscard]] OpenGlConvertCommandState panopainter_convert_command_state() noexcept;
[[nodiscard]] pp::foundation::Status apply_panopainter_convert_command_state(
    OpenGlConvertCommandStateDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlSavedState> snapshot_opengl_state(
    OpenGlStateSnapshotDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status restore_opengl_state(
    const OpenGlSavedState& state,
    OpenGlStateRestoreDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlRuntimeInfo> query_opengl_runtime_info(
    OpenGlRuntimeInfoDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::vector<std::string>> query_opengl_extensions(
    OpenGlExtensionQueryDispatch dispatch);
[[nodiscard]] OpenGlDefaultClear panopainter_default_clear() noexcept;
[[nodiscard]] pp::foundation::Status clear_panopainter_default_target(OpenGlClearDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status clear_opengl_render_target(
    OpenGlDefaultClear clear,
    OpenGlClearDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status apply_opengl_clear_color(
    std::array<float, 4> color,
    OpenGlClearColorDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status clear_opengl_color_buffer_with_write_mask(
    OpenGlColorMaskedClear clear,
    OpenGlColorMaskedClearDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status apply_opengl_color_write_mask(
    OpenGlColorWriteMask mask,
    OpenGlColorWriteMaskDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status activate_opengl_texture_unit(
    std::uint32_t unit_index,
    OpenGlActiveTextureDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status apply_opengl_viewport(
    OpenGlViewportRect viewport,
    OpenGlViewportDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlViewportRect> query_opengl_viewport(
    OpenGlViewportQueryDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::array<float, 4>> query_opengl_clear_color(
    OpenGlClearColorQueryDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status apply_opengl_scissor_rect(
    OpenGlScissorRect scissor,
    OpenGlScissorDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status apply_opengl_scissor_test(
    bool enabled,
    OpenGlScissorTestDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status apply_opengl_capability(
    std::uint32_t state,
    bool enabled,
    OpenGlCapabilityDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<bool> query_opengl_capability_state(
    std::uint32_t state,
    OpenGlCapabilityStateQueryDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status apply_opengl_render_platform_hints(
    OpenGlRenderPlatformHintDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status apply_opengl_debug_output_states(
    OpenGlDebugOutputStateDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status clear_opengl_buffers(
    std::uint32_t mask,
    OpenGlBufferClearDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::uint32_t> allocate_opengl_texture_2d(
    OpenGlTexture2DAllocation allocation,
    OpenGlTexture2DAllocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_texture_2d(
    std::uint32_t texture_id,
    OpenGlTexture2DDeleteDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_texture_objects(
    std::span<const std::uint32_t> texture_ids,
    OpenGlTexture2DDeleteDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::uint32_t> allocate_opengl_texture_cube(
    OpenGlTextureCubeAllocation allocation,
    OpenGlTextureCubeAllocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status bind_opengl_texture_2d(
    std::uint32_t texture_id,
    OpenGlTexture2DBindDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status bind_opengl_texture_cube(
    std::uint32_t texture_id,
    OpenGlTexture2DBindDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status update_opengl_texture_2d(
    OpenGlTexture2DUpdate update,
    OpenGlTexture2DUpdateDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_texture_2d_parameters(
    std::uint32_t texture_id,
    std::span<const OpenGlTextureParameter> parameters,
    OpenGlTexture2DParameterDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status copy_opengl_framebuffer_to_texture_2d(
    OpenGlTexture2DFramebufferCopy copy,
    OpenGlTexture2DFramebufferCopyDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status generate_opengl_texture_2d_mipmaps(
    std::uint32_t texture_id,
    OpenGlTexture2DMipmapDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlTexture2DReadbackResult> readback_opengl_texture_2d(
    OpenGlTexture2DReadback readback,
    OpenGlTexture2DReadbackDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status blit_opengl_framebuffer(
    OpenGlFramebufferBlit blit,
    OpenGlFramebufferBlitDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status readback_opengl_framebuffer(
    OpenGlFramebufferReadback readback,
    OpenGlFramebufferReadbackDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlFramebufferBindingState> bind_opengl_framebuffer_for_draw_read(
    std::uint32_t framebuffer,
    OpenGlFramebufferBindDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status restore_opengl_framebuffer_binding(
    OpenGlFramebufferBindingState binding,
    OpenGlFramebufferRestoreDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlRenderTargetFramebufferAllocationResult> allocate_opengl_render_target_framebuffer(
    std::uint32_t texture_id,
    std::uint32_t depth_renderbuffer_id,
    OpenGlRenderTargetFramebufferAllocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_framebuffer(
    std::uint32_t framebuffer_id,
    OpenGlFramebufferDeleteDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::uint32_t> allocate_opengl_pixel_buffer(
    OpenGlPixelBufferAllocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::uint32_t> readback_opengl_framebuffer_to_pixel_buffer(
    std::int32_t width,
    std::int32_t height,
    OpenGlReadbackFormat format,
    OpenGlPixelBufferReadbackDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<void*> map_opengl_pixel_buffer(
    std::uint32_t buffer_id,
    std::int32_t width,
    std::int32_t height,
    OpenGlReadbackFormat format,
    OpenGlPixelBufferMapDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status unmap_opengl_pixel_buffer(
    std::uint32_t buffer_id,
    OpenGlPixelBufferUnmapDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_pixel_buffer(
    std::uint32_t buffer_id,
    OpenGlPixelBufferDeleteDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::uint32_t> allocate_opengl_depth_renderbuffer(
    std::int32_t width,
    std::int32_t height,
    OpenGlDepthRenderbufferAllocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_renderbuffer(
    std::uint32_t renderbuffer_id,
    OpenGlRenderbufferDeleteDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status attach_opengl_depth_renderbuffer(
    std::uint32_t renderbuffer_id,
    OpenGlDepthRenderbufferAttachmentDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::uint32_t> create_opengl_sampler(
    std::span<const OpenGlTextureParameter> parameters,
    OpenGlSamplerCreateDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_sampler_parameters(
    std::uint32_t sampler_id,
    std::span<const OpenGlTextureParameter> parameters,
    OpenGlSamplerParameterDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_sampler_border_color(
    std::uint32_t sampler_id,
    std::uint32_t parameter,
    const float* rgba,
    OpenGlSamplerBorderDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status bind_opengl_sampler_object(
    std::uint32_t unit,
    std::uint32_t sampler_id,
    OpenGlSamplerBindDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status use_opengl_program(
    std::uint32_t program_id,
    OpenGlProgramUseDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_program(
    std::uint32_t program_id,
    OpenGlProgramDeleteDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_uniform_vec4(
    std::int32_t location,
    const float* values,
    OpenGlUniformVec4Dispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_uniform_vec3(
    std::int32_t location,
    const float* values,
    OpenGlUniformVec3Dispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_uniform_vec2(
    std::int32_t location,
    const float* values,
    OpenGlUniformVec2Dispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_uniform_mat4(
    std::int32_t location,
    const float* values,
    OpenGlUniformMat4Dispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_uniform_int(
    std::int32_t location,
    std::int32_t value,
    OpenGlUniformIntDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status set_opengl_uniform_float(
    std::int32_t location,
    float value,
    OpenGlUniformFloatDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::int32_t> get_opengl_attribute_location(
    std::uint32_t program_id,
    const char* attribute_name,
    OpenGlAttributeLocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlShaderCompileInfo> compile_opengl_shader_source(
    std::uint32_t stage,
    const char* source,
    char* info_log,
    std::int32_t info_log_capacity,
    OpenGlShaderCompileDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_shader(
    std::uint32_t shader_id,
    OpenGlShaderDeleteDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlProgramLinkInfo> link_opengl_shader_program(
    std::uint32_t vertex_shader_id,
    std::uint32_t fragment_shader_id,
    std::span<const OpenGlAttributeBinding> attribute_bindings,
    char* info_log,
    std::int32_t info_log_capacity,
    OpenGlProgramLinkDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::int32_t> query_opengl_program_integer(
    std::uint32_t program_id,
    std::uint32_t query,
    OpenGlProgramIntegerDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlActiveUniformInfo> get_opengl_active_uniform(
    std::uint32_t program_id,
    std::uint32_t index,
    char* name,
    std::int32_t name_capacity,
    OpenGlActiveUniformDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<std::int32_t> get_opengl_uniform_location(
    std::uint32_t program_id,
    const char* uniform_name,
    OpenGlUniformLocationDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Result<OpenGlMeshObjects> create_opengl_mesh_objects(
    OpenGlMeshUpload upload,
    OpenGlMeshCreateDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status upload_opengl_buffer_data(
    OpenGlBufferUpload upload,
    OpenGlBufferUploadDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status draw_opengl_mesh(
    OpenGlMeshDraw draw,
    OpenGlMeshDrawDispatch dispatch) noexcept;
[[nodiscard]] pp::foundation::Status delete_opengl_mesh_objects(
    OpenGlMeshDelete objects,
    OpenGlMeshDeleteDispatch dispatch) noexcept;

[[nodiscard]] std::uint32_t extension_count_query() noexcept;
[[nodiscard]] std::uint32_t extension_string_name() noexcept;
[[nodiscard]] std::uint32_t no_error_code() noexcept;
[[nodiscard]] const char* opengl_error_name(std::uint32_t error_code) noexcept;
[[nodiscard]] std::uint32_t texture_upload_type_for_internal_format(std::uint32_t internal_format) noexcept;
[[nodiscard]] std::uint32_t unsigned_byte_component_type() noexcept;
[[nodiscard]] std::uint32_t rgba_pixel_format() noexcept;
[[nodiscard]] OpenGlPixelFormat texture_format_for_channel_count(std::uint32_t channel_count) noexcept;
[[nodiscard]] OpenGlRendererTextureFormat texture_format_for_renderer_format(
    pp::renderer::TextureFormat format) noexcept;
[[nodiscard]] OpenGlReadbackFormat rgba8_readback_format() noexcept;
[[nodiscard]] OpenGlReadbackFormat rgba32f_readback_format() noexcept;
[[nodiscard]] std::uint64_t readback_byte_count(
    OpenGlReadbackFormat format,
    std::uint32_t width,
    std::uint32_t height) noexcept;
[[nodiscard]] std::uint32_t pixel_pack_buffer_target() noexcept;
[[nodiscard]] std::uint32_t pixel_unpack_buffer_target() noexcept;
[[nodiscard]] std::uint32_t pixel_buffer_stream_read_usage() noexcept;
[[nodiscard]] std::uint32_t pixel_buffer_map_read_access() noexcept;
[[nodiscard]] std::uint32_t texture_2d_target() noexcept;
[[nodiscard]] std::uint32_t renderbuffer_target() noexcept;
[[nodiscard]] std::uint32_t depth_component24_format() noexcept;
[[nodiscard]] std::uint32_t framebuffer_target() noexcept;
[[nodiscard]] std::uint32_t draw_framebuffer_target() noexcept;
[[nodiscard]] std::uint32_t read_framebuffer_target() noexcept;
[[nodiscard]] std::uint32_t draw_framebuffer_binding_query() noexcept;
[[nodiscard]] std::uint32_t read_framebuffer_binding_query() noexcept;
[[nodiscard]] std::uint32_t framebuffer_color_attachment() noexcept;
[[nodiscard]] std::uint32_t framebuffer_depth_attachment() noexcept;
[[nodiscard]] std::uint32_t framebuffer_complete_status() noexcept;
[[nodiscard]] std::uint32_t default_framebuffer_id() noexcept;
[[nodiscard]] const char* framebuffer_status_name(std::uint32_t status) noexcept;
[[nodiscard]] std::uint32_t framebuffer_color_buffer_mask() noexcept;
[[nodiscard]] std::uint32_t framebuffer_depth_buffer_mask() noexcept;
[[nodiscard]] std::uint32_t framebuffer_stencil_buffer_mask() noexcept;
[[nodiscard]] std::uint32_t clear_mask_for_render_pass(
    pp::renderer::RenderPassDesc desc) noexcept;
[[nodiscard]] OpenGlClearValues clear_values_for_render_pass(
    pp::renderer::RenderPassDesc desc) noexcept;
[[nodiscard]] std::uint32_t color_write_mask_query() noexcept;
[[nodiscard]] std::uint32_t framebuffer_blit_filter(bool linear) noexcept;
[[nodiscard]] OpenGlEnumMapping blit_filter_for_renderer_filter(
    pp::renderer::BlitFilter filter) noexcept;
[[nodiscard]] std::uint32_t primitive_mode_for_renderer_topology(
    pp::renderer::PrimitiveTopology topology) noexcept;
[[nodiscard]] std::uint32_t index_type_for_index_size(std::uint32_t index_size_bytes) noexcept;
[[nodiscard]] std::uint32_t primitive_mode_for_fill_count(std::uint32_t vertex_or_index_count) noexcept;
[[nodiscard]] std::uint32_t primitive_mode_for_stroke_count(std::uint32_t vertex_or_index_count) noexcept;
[[nodiscard]] std::uint32_t array_buffer_target() noexcept;
[[nodiscard]] std::uint32_t element_array_buffer_target() noexcept;
[[nodiscard]] std::uint32_t static_draw_buffer_usage() noexcept;
[[nodiscard]] std::uint32_t vertex_attribute_float_component_type() noexcept;
[[nodiscard]] std::uint32_t vertex_attribute_not_normalized() noexcept;
[[nodiscard]] std::uint32_t vertex_shader_stage() noexcept;
[[nodiscard]] std::uint32_t fragment_shader_stage() noexcept;
[[nodiscard]] std::uint32_t shader_compile_status_query() noexcept;
[[nodiscard]] std::uint32_t program_link_status_query() noexcept;
[[nodiscard]] std::uint32_t active_uniform_count_query() noexcept;
[[nodiscard]] std::uint32_t matrix_uniform_not_transposed() noexcept;
[[nodiscard]] std::uint32_t debug_severity_notification() noexcept;
[[nodiscard]] std::uint32_t debug_severity_low() noexcept;
[[nodiscard]] std::uint32_t debug_severity_medium() noexcept;
[[nodiscard]] std::uint32_t debug_severity_high() noexcept;
[[nodiscard]] std::uint32_t debug_output_state() noexcept;
[[nodiscard]] std::uint32_t debug_output_synchronous_state() noexcept;
[[nodiscard]] std::uint32_t version_string_name() noexcept;
[[nodiscard]] std::uint32_t vendor_string_name() noexcept;
[[nodiscard]] std::uint32_t renderer_string_name() noexcept;
[[nodiscard]] std::uint32_t shading_language_version_string_name() noexcept;
[[nodiscard]] std::uint32_t viewport_query() noexcept;
[[nodiscard]] OpenGlViewportRect viewport_for_renderer_viewport(
    pp::renderer::Viewport viewport) noexcept;
[[nodiscard]] std::uint32_t color_clear_value_query() noexcept;
[[nodiscard]] std::uint32_t current_program_query() noexcept;
[[nodiscard]] std::uint32_t active_texture_query() noexcept;
[[nodiscard]] std::uint32_t texture_binding_2d_query() noexcept;
[[nodiscard]] std::uint32_t texture_binding_cube_map_query() noexcept;
[[nodiscard]] std::uint32_t sampler_binding_query() noexcept;
[[nodiscard]] std::uint32_t blend_state() noexcept;
[[nodiscard]] std::uint32_t depth_test_state() noexcept;
[[nodiscard]] OpenGlEnumMapping compare_function_for_renderer_compare_op(
    pp::renderer::CompareOp op) noexcept;
[[nodiscard]] OpenGlDepthState depth_state_for_renderer_depth_state(
    pp::renderer::DepthState state) noexcept;
[[nodiscard]] std::uint32_t scissor_test_state() noexcept;
[[nodiscard]] OpenGlScissorRect scissor_rect_for_renderer_scissor(
    pp::renderer::ScissorRect scissor) noexcept;
[[nodiscard]] std::uint32_t program_point_size_state() noexcept;
[[nodiscard]] std::uint32_t line_smooth_state() noexcept;
[[nodiscard]] std::uint32_t source_alpha_blend_factor() noexcept;
[[nodiscard]] std::uint32_t one_minus_source_alpha_blend_factor() noexcept;
[[nodiscard]] std::uint32_t add_blend_equation() noexcept;
[[nodiscard]] std::uint32_t max_blend_equation() noexcept;
[[nodiscard]] OpenGlEnumMapping blend_factor_for_renderer_factor(
    pp::renderer::BlendFactor factor) noexcept;
[[nodiscard]] OpenGlEnumMapping blend_equation_for_renderer_op(
    pp::renderer::BlendOp op) noexcept;
[[nodiscard]] OpenGlBlendState blend_state_for_renderer_blend_state(
    pp::renderer::BlendState state) noexcept;
[[nodiscard]] std::uint32_t rgba8_internal_format() noexcept;
[[nodiscard]] std::uint32_t rgba16f_internal_format() noexcept;
[[nodiscard]] std::uint32_t rgba32f_internal_format() noexcept;
[[nodiscard]] std::uint8_t color_write_disabled() noexcept;
[[nodiscard]] std::uint8_t color_write_enabled() noexcept;
[[nodiscard]] OpenGlColorWriteMask color_write_mask_for_renderer_blend_state(
    pp::renderer::BlendState state) noexcept;
[[nodiscard]] std::uint32_t linear_texture_filter() noexcept;
[[nodiscard]] std::uint32_t linear_mipmap_linear_texture_filter() noexcept;
[[nodiscard]] std::uint32_t nearest_texture_filter() noexcept;
[[nodiscard]] std::uint32_t repeat_texture_wrap() noexcept;
[[nodiscard]] std::uint32_t clamp_to_edge_texture_wrap() noexcept;
[[nodiscard]] std::uint32_t clamp_to_border_texture_wrap() noexcept;
[[nodiscard]] OpenGlEnumMapping sampler_filter_for_renderer_filter(
    pp::renderer::SamplerFilter filter) noexcept;
[[nodiscard]] OpenGlEnumMapping sampler_min_filter_for_renderer_filters(
    pp::renderer::SamplerFilter min_filter,
    pp::renderer::SamplerFilter mip_filter) noexcept;
[[nodiscard]] OpenGlEnumMapping sampler_address_mode_for_renderer_mode(
    pp::renderer::SamplerAddressMode mode) noexcept;
[[nodiscard]] OpenGlSamplerState sampler_state_for_renderer_sampler_desc(
    pp::renderer::SamplerDesc desc) noexcept;
[[nodiscard]] std::uint32_t active_texture_unit(std::uint32_t unit_index) noexcept;
[[nodiscard]] std::uint32_t texture_cube_map_target() noexcept;
[[nodiscard]] std::uint32_t cube_map_allocation_face_texture_target(std::uint32_t face_index) noexcept;
[[nodiscard]] std::span<const std::uint32_t> panopainter_cube_face_texture_targets() noexcept;
[[nodiscard]] std::uint32_t cube_face_texture_target(std::uint32_t face_index) noexcept;
[[nodiscard]] std::span<const OpenGlTextureParameter> default_render_target_texture_parameters() noexcept;
[[nodiscard]] std::array<OpenGlTextureParameter, 5> sampler_parameters_for_filter_wrap(
    std::uint32_t filter,
    std::uint32_t wrap) noexcept;
[[nodiscard]] std::array<OpenGlTextureParameter, 2> sampler_filter_parameters(
    std::uint32_t filter_min,
    std::uint32_t filter_mag) noexcept;
[[nodiscard]] std::uint32_t sampler_border_color_parameter_name() noexcept;
[[nodiscard]] OpenGlWindowsWglContextConfig windows_wgl_core_context_3_3_config() noexcept;

}
