mirror of
https://github.com/Ed94/VEFontCache-Odin.git
synced 2025-08-06 06:52:44 -07:00
963 lines
38 KiB
Odin
963 lines
38 KiB
Odin
// 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
|
|
|
|
...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_image img, sg_sampler smp)
|
|
|
|
NOTE: the img 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(img: sg.Image, 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,
|
|
}
|
|
|