// machine generated, do not edit

package sokol_gl

/*

    sokol_gl.h -- OpenGL 1.x style rendering on top of sokol_gfx.h

    Project URL: https://github.com/floooh/sokol

    Do this:
        #define SOKOL_IMPL or
        #define SOKOL_GL_IMPL
    before you include this file in *one* C or C++ file to create the
    implementation.

    The following defines are used by the implementation to select the
    platform-specific embedded shader code (these are the same defines as
    used by sokol_gfx.h and sokol_app.h):

    SOKOL_GLCORE
    SOKOL_GLES3
    SOKOL_D3D11
    SOKOL_METAL
    SOKOL_WGPU
    SOKOL_VULKAN

    ...optionally provide the following macros to override defaults:

    SOKOL_ASSERT(c)     - your own assert macro (default: assert(c))
    SOKOL_GL_API_DECL   - public function declaration prefix (default: extern)
    SOKOL_API_DECL      - same as SOKOL_GL_API_DECL
    SOKOL_API_IMPL      - public function implementation prefix (default: -)
    SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))

    If sokol_gl.h is compiled as a DLL, define the following before
    including the declaration or implementation:

    SOKOL_DLL

    On Windows, SOKOL_DLL will define SOKOL_GL_API_DECL as __declspec(dllexport)
    or __declspec(dllimport) as needed.

    Include the following headers before including sokol_gl.h:

        sokol_gfx.h

    Matrix functions have been taken from MESA and Regal.

    FEATURE OVERVIEW:
    =================
    sokol_gl.h implements a subset of the OpenGLES 1.x feature set useful for
    when you just want to quickly render a bunch of triangles or
    lines without having to mess with buffers and shaders.

    The current feature set is mostly useful for debug visualizations
    and simple UI-style 2D rendering:

    What's implemented:
        - vertex components:
            - position (x, y, z)
            - 2D texture coords (u, v)
            - color (r, g, b, a)
        - primitive types:
            - triangle list and strip
            - line list and strip
            - quad list (TODO: quad strips)
            - point list
        - one texture layer (no multi-texturing)
        - viewport and scissor-rect with selectable origin (top-left or bottom-left)
        - all GL 1.x matrix stack functions, and additionally equivalent
          functions for gluPerspective and gluLookat

    Notable GLES 1.x features that are *NOT* implemented:
        - vertex lighting (this is the most likely GL feature that might be added later)
        - vertex arrays (although providing whole chunks of vertex data at once
          might be a useful feature for a later version)
        - texture coordinate generation
        - line width
        - all pixel store functions
        - no ALPHA_TEST
        - no clear functions (clearing is handled by the sokol-gfx render pass)
        - fog

    Notable differences to GL:
        - No "enum soup" for render states etc, instead there's a
          'pipeline stack', this is similar to GL's matrix stack,
          but for pipeline-state-objects. The pipeline object at
          the top of the pipeline stack defines the active set of render states
        - All angles are in radians, not degrees (note the sgl_rad() and
          sgl_deg() conversion functions)
        - No enable/disable state for scissor test, this is always enabled

    STEP BY STEP:
    =============
    --- To initialize sokol-gl, call:

            sgl_setup(const sgl_desc_t* desc)

        NOTE that sgl_setup() must be called *after* initializing sokol-gfx
        (via sg_setup). This is because sgl_setup() needs to create
        sokol-gfx resource objects.

        If you're intending to render to the default pass, and also don't
        want to tweak memory usage, and don't want any logging output you can
        just keep sgl_desc_t zero-initialized:

            sgl_setup(&(sgl_desc_t*){ 0 });

        In this case, sokol-gl will create internal sg_pipeline objects that
        are compatible with the sokol-app default framebuffer.

        I would recommend to at least install a logging callback so that
        you'll see any warnings and errors. The easiest way is through
        sokol_log.h:

            #include "sokol_log.h"

            sgl_setup(&(sgl_desc_t){
                .logger.func = slog_func.
            });

        If you want to render into a framebuffer with different pixel-format
        and MSAA attributes you need to provide the matching attributes in the
        sgl_setup() call:

            sgl_setup(&(sgl_desc_t*){
                .color_format = SG_PIXELFORMAT_...,
                .depth_format = SG_PIXELFORMAT_...,
                .sample_count = ...,
            });

        To reduce memory usage, or if you need to create more then the default number of
        contexts, pipelines, vertices or draw commands, set the following sgl_desc_t
        members:

            .context_pool_size      (default: 4)
            .pipeline_pool_size     (default: 64)
            .max_vertices       (default: 64k)
            .max_commands       (default: 16k)

        Finally you can change the face winding for front-facing triangles
        and quads:

            .face_winding    - default is SG_FACEWINDING_CCW

        The default winding for front faces is counter-clock-wise. This is
        the same as OpenGL's default, but different from sokol-gfx.

    --- Optionally create additional context objects if you want to render into
        multiple sokol-gfx render passes (or generally if you want to
        use multiple independent sokol-gl "state buckets")

            sgl_context ctx = sgl_make_context(const sgl_context_desc_t* desc)

        For details on rendering with sokol-gl contexts, search below for
        WORKING WITH CONTEXTS.

    --- Optionally create pipeline-state-objects if you need render state
        that differs from sokol-gl's default state:

            sgl_pipeline pip = sgl_make_pipeline(const sg_pipeline_desc* desc)

        ...this creates a pipeline object that's compatible with the currently
        active context, alternatively call:

            sgl_pipeline_pip = sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline_desc* desc)

        ...to create a pipeline object that's compatible with an explicitly
        provided context.

        The similarity with sokol_gfx.h's sg_pipeline type and sg_make_pipeline()
        function is intended. sgl_make_pipeline() also takes a standard
        sokol-gfx sg_pipeline_desc object to describe the render state, but
        without:
            - shader
            - vertex layout
            - color- and depth-pixel-formats
            - primitive type (lines, triangles, ...)
            - MSAA sample count
        Those will be filled in by sgl_make_pipeline(). Note that each
        call to sgl_make_pipeline() needs to create several sokol-gfx
        pipeline objects (one for each primitive type).

        'depth.write_enabled' will be forced to 'false' if the context this
        pipeline object is intended for has its depth pixel format set to
        SG_PIXELFORMAT_NONE (which means the framebuffer this context is used
        with doesn't have a depth-stencil surface).

    --- if you need to destroy sgl_pipeline objects before sgl_shutdown():

            sgl_destroy_pipeline(sgl_pipeline pip)

    --- After sgl_setup() you can call any of the sokol-gl functions anywhere
        in a frame, *except* sgl_draw(). The 'vanilla' functions
        will only change internal sokol-gl state, and not call any sokol-gfx
        functions.

    --- Unlike OpenGL, sokol-gl has a function to reset internal state to
        a known default. This is useful at the start of a sequence of
        rendering operations:

            void sgl_defaults(void)

        This will set the following default state:

            - current texture coordinate to u=0.0f, v=0.0f
            - current color to white (rgba all 1.0f)
            - current point size to 1.0f
            - unbind the current texture and texturing will be disabled
            - *all* matrices will be set to identity (also the projection matrix)
            - the default render state will be set by loading the 'default pipeline'
              into the top of the pipeline stack

        The current matrix- and pipeline-stack-depths will not be changed by
        sgl_defaults().

    --- change the currently active renderstate through the
        pipeline-stack functions, this works similar to the
        traditional GL matrix stack:

            ...load the default pipeline state on the top of the pipeline stack:

                sgl_load_default_pipeline()

            ...load a specific pipeline on the top of the pipeline stack:

                sgl_load_pipeline(sgl_pipeline pip)

            ...push and pop the pipeline stack:
                sgl_push_pipeline()
                sgl_pop_pipeline()

    --- control texturing with:

            sgl_enable_texture()
            sgl_disable_texture()
            sgl_texture(sg_view tex_view, sg_sampler smp)

        NOTE: the tex_view and smp handles can be invalid (SG_INVALID_ID), in this
        case, sokol-gl will fall back to the internal default (white) texture
        and sampler.

    --- set the current viewport and scissor rect with:

            sgl_viewport(int x, int y, int w, int h, bool origin_top_left)
            sgl_scissor_rect(int x, int y, int w, int h, bool origin_top_left)

        ...or call these alternatives which take float arguments (this might allow
        to avoid casting between float and integer in more strongly typed languages
        when floating point pixel coordinates are used):

            sgl_viewportf(float x, float y, float w, float h, bool origin_top_left)
            sgl_scissor_rectf(float x, float y, float w, float h, bool origin_top_left)

        ...these calls add a new command to the internal command queue, so
        that the viewport or scissor rect are set at the right time relative
        to other sokol-gl calls.

    --- adjust the transform matrices, matrix manipulation works just like
        the OpenGL matrix stack:

        ...set the current matrix mode:

            sgl_matrix_mode_modelview()
            sgl_matrix_mode_projection()
            sgl_matrix_mode_texture()

        ...load the identity matrix into the current matrix:

            sgl_load_identity()

        ...translate, rotate and scale the current matrix:

            sgl_translate(float x, float y, float z)
            sgl_rotate(float angle_rad, float x, float y, float z)
            sgl_scale(float x, float y, float z)

        NOTE that all angles in sokol-gl are in radians, not in degree.
        Convert between radians and degree with the helper functions:

            float sgl_rad(float deg)        - degrees to radians
            float sgl_deg(float rad)        - radians to degrees

        ...directly load the current matrix from a float[16] array:

            sgl_load_matrix(const float m[16])
            sgl_load_transpose_matrix(const float m[16])

        ...directly multiply the current matrix from a float[16] array:

            sgl_mult_matrix(const float m[16])
            sgl_mult_transpose_matrix(const float m[16])

        The memory layout of those float[16] arrays is the same as in OpenGL.

        ...more matrix functions:

            sgl_frustum(float left, float right, float bottom, float top, float near, float far)
            sgl_ortho(float left, float right, float bottom, float top, float near, float far)
            sgl_perspective(float fov_y, float aspect, float near, float far)
            sgl_lookat(float eye_x, float eye_y, float eye_z, float center_x, float center_y, float center_z, float up_x, float up_y, float up_z)

        These functions work the same as glFrustum(), glOrtho(), gluPerspective()
        and gluLookAt().

        ...and finally to push / pop the current matrix stack:

            sgl_push_matrix(void)
            sgl_pop_matrix(void)

        Again, these work the same as glPushMatrix() and glPopMatrix().

    --- perform primitive rendering:

        ...set the current texture coordinate and color 'registers' with or
        point size with:

            sgl_t2f(float u, float v)   - set current texture coordinate
            sgl_c*(...)                 - set current color
            sgl_point_size(float size)  - set current point size

        There are several functions for setting the color (as float values,
        unsigned byte values, packed as unsigned 32-bit integer, with
        and without alpha).

        NOTE that these are the only functions that can be called both inside
        sgl_begin_*() / sgl_end() and outside.

        Also NOTE that point size is currently hardwired to 1.0f if the D3D11
        backend is used.

        ...start a primitive vertex sequence with:

            sgl_begin_points()
            sgl_begin_lines()
            sgl_begin_line_strip()
            sgl_begin_triangles()
            sgl_begin_triangle_strip()
            sgl_begin_quads()

        ...after sgl_begin_*() specify vertices:

            sgl_v*(...)
            sgl_v*_t*(...)
            sgl_v*_c*(...)
            sgl_v*_t*_c*(...)

        These functions write a new vertex to sokol-gl's internal vertex buffer,
        optionally with texture-coords and color. If the texture coordinate
        and/or color is missing, it will be taken from the current texture-coord
        and color 'register'.

        ...finally, after specifying vertices, call:

            sgl_end()

        This will record a new draw command in sokol-gl's internal command
        list, or it will extend the previous draw command if no relevant
        state has changed since the last sgl_begin/end pair.

    --- inside a sokol-gfx rendering pass, call the sgl_draw() function
        to render the currently active context:

            sgl_draw()

        ...or alternatively call:

            sgl_context_draw(ctx)

        ...to render an explicitly provided context.

        This will render everything that has been recorded in the context since
        the last call to sgl_draw() through sokol-gfx, and will 'rewind' the internal
        vertex-, uniform- and command-buffers.

    --- each sokol-gl context tracks internal error states which can
        be obtains via:

            sgl_error_t sgl_error()

        ...alternatively with an explicit context argument:

            sgl_error_t sgl_context_error(ctx);

        ...this returns a struct with the following booleans:

            .any                - true if any of the below errors is true
            .vertices_full      - internal vertex buffer is full (checked in sgl_end())
            .uniforms_full      - the internal uniforms buffer is full (checked in sgl_end())
            .commands_full      - the internal command buffer is full (checked in sgl_end())
            .stack_overflow     - matrix- or pipeline-stack overflow
            .stack_underflow    - matrix- or pipeline-stack underflow
            .no_context         - the active context no longer exists

        ...depending on the above error state, sgl_draw() may skip rendering
        completely, or only draw partial geometry

    --- you can get the number of recorded vertices and draw commands in the current
        frame and active sokol-gl context via:

            int sgl_num_vertices()
            int sgl_num_commands()

        ...this allows you to check whether the vertex or command pools are running
        full before the overflow actually happens (in this case you could also
        check the error booleans in the result of sgl_error()).

    RENDER LAYERS
    =============
    Render layers allow to split sokol-gl rendering into separate draw-command
    groups which can then be rendered separately in a sokol-gfx draw pass. This
    allows to mix/interleave sokol-gl rendering with other render operations.

    Layered rendering is controlled through two functions:

        sgl_layer(int layer_id)
        sgl_draw_layer(int layer_id)

    (and the context-variant sgl_draw_layer(): sgl_context_draw_layer()

    The sgl_layer() function sets the 'current layer', any sokol-gl calls
    which internally record draw commands will also store the current layer
    in the draw command, and later in a sokol-gfx render pass, a call
    to sgl_draw_layer() will only render the draw commands that have
    a matching layer.

    The default layer is '0', this is active after sokol-gl setup, and
    is also restored at the start of a new frame (but *not* by calling
    sgl_defaults()).

    NOTE that calling sgl_draw() is equivalent with sgl_draw_layer(0)
    (in general you should either use either use sgl_draw() or
    sgl_draw_layer() in an application, but not both).

    WORKING WITH CONTEXTS:
    ======================
    If you want to render to more than one sokol-gfx render pass you need to
    work with additional sokol-gl context objects (one context object for
    each offscreen rendering pass, in addition to the implicitly created
    'default context'.

    All sokol-gl state is tracked per context, and there is always a "current
    context" (with the notable exception that the currently set context is
    destroyed, more on that later).

    Using multiple contexts can also be useful if you only render in
    a single pass, but want to maintain multiple independent "state buckets".

    To create new context object, call:

        sgl_context ctx = sgl_make_context(&(sgl_context_desc){
            .max_vertices = ...,        // default: 64k
            .max_commands = ...,        // default: 16k
            .color_format = ...,
            .depth_format = ...,
            .sample_count = ...,
        });

    The color_format, depth_format and sample_count items must be compatible
    with the render pass the sgl_draw() or sgL_context_draw() function
    will be called in.

    Creating a context does *not* make the context current. To do this, call:

        sgl_set_context(ctx);

    The currently active context will implicitly be used by most sokol-gl functions
    which don't take an explicit context handle as argument.

    To switch back to the default context, pass the global constant SGL_DEFAULT_CONTEXT:

        sgl_set_context(SGL_DEFAULT_CONTEXT);

    ...or alternatively use the function sgl_default_context() instead of the
    global constant:

        sgl_set_context(sgl_default_context());

    To get the currently active context, call:

        sgl_context cur_ctx = sgl_get_context();

    The following functions exist in two variants, one which use the currently
    active context (set with sgl_set_context()), and another version which
    takes an explicit context handle instead:

        sgl_make_pipeline() vs sgl_context_make_pipeline()
        sgl_error() vs sgl_context_error();
        sgl_draw() vs sgl_context_draw();

    Except for using the currently active context versus a provided context
    handle, the two variants are exactlyidentical, e.g. the following
    code sequences do the same thing:

        sgl_set_context(ctx);
        sgl_pipeline pip = sgl_make_pipeline(...);
        sgl_error_t err = sgl_error();
        sgl_draw();

        vs

        sgl_pipeline pip = sgl_context_make_pipeline(ctx, ...);
        sgl_error_t err = sgl_context_error(ctx);
        sgl_context_draw(ctx);

    Destroying the currently active context is a 'soft error'. All following
    calls which require a currently active context will silently fail,
    and sgl_error() will return SGL_ERROR_NO_CONTEXT.

    UNDER THE HOOD:
    ===============
    sokol_gl.h works by recording vertex data and rendering commands into
    memory buffers, and then drawing the recorded commands via sokol_gfx.h

    The only functions which call into sokol_gfx.h are:
        - sgl_setup()
        - sgl_shutdown()
        - sgl_draw() (and variants)

    sgl_setup() must be called after initializing sokol-gfx.
    sgl_shutdown() must be called before shutting down sokol-gfx.
    sgl_draw() must be called once per frame inside a sokol-gfx render pass.

    All other sokol-gl function can be called anywhere in a frame, since
    they just record data into memory buffers owned by sokol-gl.

    What happens in:

        sgl_setup():
            Unique resources shared by all contexts are created:
                - a shader object (using embedded shader source or byte code)
                - an 8x8 white default texture
            The default context is created, which involves:
                - 3 memory buffers are created, one for vertex data,
                  one for uniform data, and one for commands
                - a dynamic vertex buffer is created
                - the default sgl_pipeline object is created, which involves
                  creating 5 sg_pipeline objects

            One vertex is 24 bytes:
                - float3 position
                - float2 texture coords
                - uint32_t color

            One uniform block is 128 bytes:
                - mat4 model-view-projection matrix
                - mat4 texture matrix

            One draw command is ca. 24 bytes for the actual
            command code plus command arguments.

            Each sgl_end() consumes one command, and one uniform block
            (only when the matrices have changed).
            The required size for one sgl_begin/end pair is (at most):

                (152 + 24 * num_verts) bytes

        sgl_shutdown():
            - all sokol-gfx resources (buffer, shader, default-texture and
              all pipeline objects) are destroyed
            - the 3 memory buffers are freed

        sgl_draw() (and variants)
            - copy all recorded vertex data into the dynamic sokol-gfx buffer
              via a call to sg_update_buffer()
            - for each recorded command:
                - if the layer number stored in the command doesn't match
                  the layer that's to be rendered, skip to the next
                  command
                - if it's a viewport command, call sg_apply_viewport()
                - if it's a scissor-rect command, call sg_apply_scissor_rect()
                - if it's a draw command:
                    - depending on what has changed since the last draw command,
                      call sg_apply_pipeline(), sg_apply_bindings() and
                      sg_apply_uniforms()
                    - finally call sg_draw()

    All other functions only modify the internally tracked state, add
    data to the vertex, uniform and command buffers, or manipulate
    the matrix stack.

    ON DRAW COMMAND MERGING
    =======================
    Not every call to sgl_end() will automatically record a new draw command.
    If possible, the previous draw command will simply be extended,
    resulting in fewer actual draw calls later in sgl_draw().

    A draw command will be merged with the previous command if "no relevant
    state has changed" since the last sgl_end(), meaning:

    - no calls to sgl_viewport() and sgl_scissor_rect()
    - the primitive type hasn't changed
    - the primitive type isn't a 'strip type' (no line or triangle strip)
    - the pipeline state object hasn't changed
    - the current layer hasn't changed
    - none of the matrices has changed
    - none of the texture state has changed

    Merging a draw command simply means that the number of vertices
    to render in the previous draw command will be incremented by the
    number of vertices in the new draw command.

    MEMORY ALLOCATION OVERRIDE
    ==========================
    You can override the memory allocation functions at initialization time
    like this:

        void* my_alloc(size_t size, void* user_data) {
            return malloc(size);
        }

        void my_free(void* ptr, void* user_data) {
            free(ptr);
        }

        ...
            sgl_setup(&(sgl_desc_t){
                // ...
                .allocator = {
                    .alloc_fn = my_alloc,
                    .free_fn = my_free,
                    .user_data = ...;
                }
            });
        ...

    If no overrides are provided, malloc and free will be used.


    ERROR REPORTING AND LOGGING
    ===========================
    To get any logging information at all you need to provide a logging callback in the setup call,
    the easiest way is to use sokol_log.h:

        #include "sokol_log.h"

        sgl_setup(&(sgl_desc_t){
            // ...
            .logger.func = slog_func
        });

    To override logging with your own callback, first write a logging function like this:

        void my_log(const char* tag,                // e.g. 'sgl'
                    uint32_t log_level,             // 0=panic, 1=error, 2=warn, 3=info
                    uint32_t log_item_id,           // SGL_LOGITEM_*
                    const char* message_or_null,    // a message string, may be nullptr in release mode
                    uint32_t line_nr,               // line number in sokol_gl.h
                    const char* filename_or_null,   // source filename, may be nullptr in release mode
                    void* user_data)
        {
            ...
        }

    ...and then setup sokol-gl like this:

        sgl_setup(&(sgl_desc_t){
            .logger = {
                .func = my_log,
                .user_data = my_user_data,
            }
        });

    The provided logging function must be reentrant (e.g. be callable from
    different threads).

    If you don't want to provide your own custom logger it is highly recommended to use
    the standard logger in sokol_log.h instead, otherwise you won't see any warnings or
    errors.


    LICENSE
    =======
    zlib/libpng license

    Copyright (c) 2018 Andre Weissflog

    This software is provided 'as-is', without any express or implied warranty.
    In no event will the authors be held liable for any damages arising from the
    use of this software.

    Permission is granted to anyone to use this software for any purpose,
    including commercial applications, and to alter it and redistribute it
    freely, subject to the following restrictions:

        1. The origin of this software must not be misrepresented; you must not
        claim that you wrote the original software. If you use this software in a
        product, an acknowledgment in the product documentation would be
        appreciated but is not required.

        2. Altered source versions must be plainly marked as such, and must not
        be misrepresented as being the original software.

        3. This notice may not be removed or altered from any source
        distribution.

*/
import sg "../gfx"

import "core:c"

_ :: c

SOKOL_DEBUG :: #config(SOKOL_DEBUG, ODIN_DEBUG)

DEBUG :: #config(SOKOL_GL_DEBUG, SOKOL_DEBUG)
USE_GL :: #config(SOKOL_USE_GL, false)
USE_DLL :: #config(SOKOL_DLL, false)

when ODIN_OS == .Windows {
    when USE_DLL {
        when USE_GL {
            when DEBUG { foreign import sokol_gl_clib { "../sokol_dll_windows_x64_gl_debug.lib" } }
            else       { foreign import sokol_gl_clib { "../sokol_dll_windows_x64_gl_release.lib" } }
        } else {
            when DEBUG { foreign import sokol_gl_clib { "../sokol_dll_windows_x64_d3d11_debug.lib" } }
            else       { foreign import sokol_gl_clib { "../sokol_dll_windows_x64_d3d11_release.lib" } }
        }
    } else {
        when USE_GL {
            when DEBUG { foreign import sokol_gl_clib { "sokol_gl_windows_x64_gl_debug.lib" } }
            else       { foreign import sokol_gl_clib { "sokol_gl_windows_x64_gl_release.lib" } }
        } else {
            when DEBUG { foreign import sokol_gl_clib { "sokol_gl_windows_x64_d3d11_debug.lib" } }
            else       { foreign import sokol_gl_clib { "sokol_gl_windows_x64_d3d11_release.lib" } }
        }
    }
} else when ODIN_OS == .Darwin {
    when USE_DLL {
             when  USE_GL && ODIN_ARCH == .arm64 &&  DEBUG { foreign import sokol_gl_clib { "../dylib/sokol_dylib_macos_arm64_gl_debug.dylib" } }
        else when  USE_GL && ODIN_ARCH == .arm64 && !DEBUG { foreign import sokol_gl_clib { "../dylib/sokol_dylib_macos_arm64_gl_release.dylib" } }
        else when  USE_GL && ODIN_ARCH == .amd64 &&  DEBUG { foreign import sokol_gl_clib { "../dylib/sokol_dylib_macos_x64_gl_debug.dylib" } }
        else when  USE_GL && ODIN_ARCH == .amd64 && !DEBUG { foreign import sokol_gl_clib { "../dylib/sokol_dylib_macos_x64_gl_release.dylib" } }
        else when !USE_GL && ODIN_ARCH == .arm64 &&  DEBUG { foreign import sokol_gl_clib { "../dylib/sokol_dylib_macos_arm64_metal_debug.dylib" } }
        else when !USE_GL && ODIN_ARCH == .arm64 && !DEBUG { foreign import sokol_gl_clib { "../dylib/sokol_dylib_macos_arm64_metal_release.dylib" } }
        else when !USE_GL && ODIN_ARCH == .amd64 &&  DEBUG { foreign import sokol_gl_clib { "../dylib/sokol_dylib_macos_x64_metal_debug.dylib" } }
        else when !USE_GL && ODIN_ARCH == .amd64 && !DEBUG { foreign import sokol_gl_clib { "../dylib/sokol_dylib_macos_x64_metal_release.dylib" } }
    } else {
        when USE_GL {
            when ODIN_ARCH == .arm64 {
                when DEBUG { foreign import sokol_gl_clib { "sokol_gl_macos_arm64_gl_debug.a" } }
                else       { foreign import sokol_gl_clib { "sokol_gl_macos_arm64_gl_release.a" } }
            } else {
                when DEBUG { foreign import sokol_gl_clib { "sokol_gl_macos_x64_gl_debug.a" } }
                else       { foreign import sokol_gl_clib { "sokol_gl_macos_x64_gl_release.a" } }
            }
        } else {
            when ODIN_ARCH == .arm64 {
                when DEBUG { foreign import sokol_gl_clib { "sokol_gl_macos_arm64_metal_debug.a" } }
                else       { foreign import sokol_gl_clib { "sokol_gl_macos_arm64_metal_release.a" } }
            } else {
                when DEBUG { foreign import sokol_gl_clib { "sokol_gl_macos_x64_metal_debug.a" } }
                else       { foreign import sokol_gl_clib { "sokol_gl_macos_x64_metal_release.a" } }
            }
        }
    }
} else when ODIN_OS == .Linux {
    when USE_DLL {
        when DEBUG { foreign import sokol_gl_clib { "sokol_gl_linux_x64_gl_debug.so" } }
        else       { foreign import sokol_gl_clib { "sokol_gl_linux_x64_gl_release.so" } }
    } else {
        when DEBUG { foreign import sokol_gl_clib { "sokol_gl_linux_x64_gl_debug.a" } }
        else       { foreign import sokol_gl_clib { "sokol_gl_linux_x64_gl_release.a" } }
    }
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
    // Feed sokol_gl_wasm_gl_debug.a or sokol_gl_wasm_gl_release.a into emscripten compiler.
    foreign import sokol_gl_clib { "env.o" }
} else {
    #panic("This OS is currently not supported")
}

@(default_calling_convention="c", link_prefix="sgl_")
foreign sokol_gl_clib {
    // setup/shutdown/misc
    setup :: proc(#by_ptr desc: Desc)  ---
    shutdown :: proc()  ---
    rad :: proc(deg: f32) -> f32 ---
    deg :: proc(rad: f32) -> f32 ---
    error :: proc() -> Error ---
    context_error :: proc(ctx: Context) -> Error ---
    // context functions
    make_context :: proc(#by_ptr desc: Context_Desc) -> Context ---
    destroy_context :: proc(ctx: Context)  ---
    set_context :: proc(ctx: Context)  ---
    get_context :: proc() -> Context ---
    default_context :: proc() -> Context ---
    // get information about recorded vertices and commands in current context
    num_vertices :: proc() -> c.int ---
    num_commands :: proc() -> c.int ---
    // draw recorded commands (call inside a sokol-gfx render pass)
    draw :: proc()  ---
    context_draw :: proc(ctx: Context)  ---
    draw_layer :: proc(#any_int layer_id: c.int)  ---
    context_draw_layer :: proc(ctx: Context, #any_int layer_id: c.int)  ---
    // create and destroy pipeline objects
    make_pipeline :: proc(#by_ptr desc: sg.Pipeline_Desc) -> Pipeline ---
    context_make_pipeline :: proc(ctx: Context, #by_ptr desc: sg.Pipeline_Desc) -> Pipeline ---
    destroy_pipeline :: proc(pip: Pipeline)  ---
    // render state functions
    defaults :: proc()  ---
    viewport :: proc(#any_int x: c.int, #any_int y: c.int, #any_int w: c.int, #any_int h: c.int, origin_top_left: bool)  ---
    viewportf :: proc(x: f32, y: f32, w: f32, h: f32, origin_top_left: bool)  ---
    scissor_rect :: proc(#any_int x: c.int, #any_int y: c.int, #any_int w: c.int, #any_int h: c.int, origin_top_left: bool)  ---
    scissor_rectf :: proc(x: f32, y: f32, w: f32, h: f32, origin_top_left: bool)  ---
    enable_texture :: proc()  ---
    disable_texture :: proc()  ---
    texture :: proc(tex_view: sg.View, smp: sg.Sampler)  ---
    layer :: proc(#any_int layer_id: c.int)  ---
    // pipeline stack functions
    load_default_pipeline :: proc()  ---
    load_pipeline :: proc(pip: Pipeline)  ---
    push_pipeline :: proc()  ---
    pop_pipeline :: proc()  ---
    // matrix stack functions
    matrix_mode_modelview :: proc()  ---
    matrix_mode_projection :: proc()  ---
    matrix_mode_texture :: proc()  ---
    load_identity :: proc()  ---
    load_matrix :: proc(m: ^f32)  ---
    load_transpose_matrix :: proc(m: ^f32)  ---
    mult_matrix :: proc(m: ^f32)  ---
    mult_transpose_matrix :: proc(m: ^f32)  ---
    rotate :: proc(angle_rad: f32, x: f32, y: f32, z: f32)  ---
    scale :: proc(x: f32, y: f32, z: f32)  ---
    translate :: proc(x: f32, y: f32, z: f32)  ---
    frustum :: proc(l: f32, r: f32, b: f32, t: f32, n: f32, f: f32)  ---
    ortho :: proc(l: f32, r: f32, b: f32, t: f32, n: f32, f: f32)  ---
    perspective :: proc(fov_y: f32, aspect: f32, z_near: f32, z_far: f32)  ---
    lookat :: proc(eye_x: f32, eye_y: f32, eye_z: f32, center_x: f32, center_y: f32, center_z: f32, up_x: f32, up_y: f32, up_z: f32)  ---
    push_matrix :: proc()  ---
    pop_matrix :: proc()  ---
    // these functions only set the internal 'current texcoord / color / point size' (valid inside or outside begin/end)
    t2f :: proc(u: f32, v: f32)  ---
    c3f :: proc(r: f32, g: f32, b: f32)  ---
    c4f :: proc(r: f32, g: f32, b: f32, a: f32)  ---
    c3b :: proc(r: u8, g: u8, b: u8)  ---
    c4b :: proc(r: u8, g: u8, b: u8, a: u8)  ---
    c1i :: proc(rgba: u32)  ---
    point_size :: proc(s: f32)  ---
    // define primitives, each begin/end is one draw command
    begin_points :: proc()  ---
    begin_lines :: proc()  ---
    begin_line_strip :: proc()  ---
    begin_triangles :: proc()  ---
    begin_triangle_strip :: proc()  ---
    begin_quads :: proc()  ---
    v2f :: proc(x: f32, y: f32)  ---
    v3f :: proc(x: f32, y: f32, z: f32)  ---
    v2f_t2f :: proc(x: f32, y: f32, u: f32, v: f32)  ---
    v3f_t2f :: proc(x: f32, y: f32, z: f32, u: f32, v: f32)  ---
    v2f_c3f :: proc(x: f32, y: f32, r: f32, g: f32, b: f32)  ---
    v2f_c3b :: proc(x: f32, y: f32, r: u8, g: u8, b: u8)  ---
    v2f_c4f :: proc(x: f32, y: f32, r: f32, g: f32, b: f32, a: f32)  ---
    v2f_c4b :: proc(x: f32, y: f32, r: u8, g: u8, b: u8, a: u8)  ---
    v2f_c1i :: proc(x: f32, y: f32, rgba: u32)  ---
    v3f_c3f :: proc(x: f32, y: f32, z: f32, r: f32, g: f32, b: f32)  ---
    v3f_c3b :: proc(x: f32, y: f32, z: f32, r: u8, g: u8, b: u8)  ---
    v3f_c4f :: proc(x: f32, y: f32, z: f32, r: f32, g: f32, b: f32, a: f32)  ---
    v3f_c4b :: proc(x: f32, y: f32, z: f32, r: u8, g: u8, b: u8, a: u8)  ---
    v3f_c1i :: proc(x: f32, y: f32, z: f32, rgba: u32)  ---
    v2f_t2f_c3f :: proc(x: f32, y: f32, u: f32, v: f32, r: f32, g: f32, b: f32)  ---
    v2f_t2f_c3b :: proc(x: f32, y: f32, u: f32, v: f32, r: u8, g: u8, b: u8)  ---
    v2f_t2f_c4f :: proc(x: f32, y: f32, u: f32, v: f32, r: f32, g: f32, b: f32, a: f32)  ---
    v2f_t2f_c4b :: proc(x: f32, y: f32, u: f32, v: f32, r: u8, g: u8, b: u8, a: u8)  ---
    v2f_t2f_c1i :: proc(x: f32, y: f32, u: f32, v: f32, rgba: u32)  ---
    v3f_t2f_c3f :: proc(x: f32, y: f32, z: f32, u: f32, v: f32, r: f32, g: f32, b: f32)  ---
    v3f_t2f_c3b :: proc(x: f32, y: f32, z: f32, u: f32, v: f32, r: u8, g: u8, b: u8)  ---
    v3f_t2f_c4f :: proc(x: f32, y: f32, z: f32, u: f32, v: f32, r: f32, g: f32, b: f32, a: f32)  ---
    v3f_t2f_c4b :: proc(x: f32, y: f32, z: f32, u: f32, v: f32, r: u8, g: u8, b: u8, a: u8)  ---
    v3f_t2f_c1i :: proc(x: f32, y: f32, z: f32, u: f32, v: f32, rgba: u32)  ---
    end :: proc()  ---
}

Log_Item :: enum i32 {
    OK,
    MALLOC_FAILED,
    MAKE_PIPELINE_FAILED,
    PIPELINE_POOL_EXHAUSTED,
    ADD_COMMIT_LISTENER_FAILED,
    CONTEXT_POOL_EXHAUSTED,
    CANNOT_DESTROY_DEFAULT_CONTEXT,
}

/*
    sgl_logger_t

    Used in sgl_desc_t to provide a custom logging and error reporting
    callback to sokol-gl.
*/
Logger :: struct {
    func : proc "c" (a0: cstring, a1: u32, a2: u32, a3: cstring, a4: u32, a5: cstring, a6: rawptr),
    user_data : rawptr,
}

// sokol_gl pipeline handle (created with sgl_make_pipeline())
Pipeline :: struct {
    id : u32,
}

// a context handle (created with sgl_make_context())
Context :: struct {
    id : u32,
}

/*
    sgl_error_t

    Errors are reset each frame after calling sgl_draw(),
    get the last error code with sgl_error()
*/
Error :: struct {
    any : bool,
    vertices_full : bool,
    uniforms_full : bool,
    commands_full : bool,
    stack_overflow : bool,
    stack_underflow : bool,
    no_context : bool,
}

/*
    sgl_context_desc_t

    Describes the initialization parameters of a rendering context.
    Creating additional contexts is useful if you want to render
    in separate sokol-gfx passes.
*/
Context_Desc :: struct {
    max_vertices : c.int,
    max_commands : c.int,
    color_format : sg.Pixel_Format,
    depth_format : sg.Pixel_Format,
    sample_count : c.int,
}

/*
    sgl_allocator_t

    Used in sgl_desc_t to provide custom memory-alloc and -free functions
    to sokol_gl.h. If memory management should be overridden, both the
    alloc and free function must be provided (e.g. it's not valid to
    override one function but not the other).
*/
Allocator :: struct {
    alloc_fn : proc "c" (a0: c.size_t, a1: rawptr) -> rawptr,
    free_fn : proc "c" (a0: rawptr, a1: rawptr),
    user_data : rawptr,
}

Desc :: struct {
    max_vertices : c.int,
    max_commands : c.int,
    context_pool_size : c.int,
    pipeline_pool_size : c.int,
    color_format : sg.Pixel_Format,
    depth_format : sg.Pixel_Format,
    sample_count : c.int,
    face_winding : sg.Face_Winding,
    allocator : Allocator,
    logger : Logger,
}

